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.
Files changed (164) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1321 -0
  3. data/LICENSE.txt +23 -0
  4. data/bin/pact +4 -0
  5. data/lib/pact/cli/generate_pact_docs.rb +4 -0
  6. data/lib/pact/cli/run_pact_verification.rb +99 -0
  7. data/lib/pact/cli/spec_criteria.rb +26 -0
  8. data/lib/pact/cli.rb +45 -0
  9. data/lib/pact/consumer/configuration/configuration_extensions.rb +90 -0
  10. data/lib/pact/consumer/configuration/dsl.rb +11 -0
  11. data/lib/pact/consumer/configuration/mock_service.rb +112 -0
  12. data/lib/pact/consumer/configuration/service_consumer.rb +51 -0
  13. data/lib/pact/consumer/configuration/service_provider.rb +40 -0
  14. data/lib/pact/consumer/configuration.rb +10 -0
  15. data/lib/pact/consumer/consumer_contract_builder.rb +82 -0
  16. data/lib/pact/consumer/consumer_contract_builders.rb +10 -0
  17. data/lib/pact/consumer/interaction_builder.rb +45 -0
  18. data/lib/pact/consumer/rspec.rb +35 -0
  19. data/lib/pact/consumer/spec_hooks.rb +40 -0
  20. data/lib/pact/consumer/world.rb +37 -0
  21. data/lib/pact/consumer.rb +7 -0
  22. data/lib/pact/doc/README.md +13 -0
  23. data/lib/pact/doc/doc_file.rb +40 -0
  24. data/lib/pact/doc/generate.rb +11 -0
  25. data/lib/pact/doc/generator.rb +82 -0
  26. data/lib/pact/doc/interaction_view_model.rb +124 -0
  27. data/lib/pact/doc/markdown/consumer_contract_renderer.rb +68 -0
  28. data/lib/pact/doc/markdown/generator.rb +26 -0
  29. data/lib/pact/doc/markdown/index_renderer.rb +43 -0
  30. data/lib/pact/doc/markdown/interaction.erb +14 -0
  31. data/lib/pact/doc/markdown/interaction_renderer.rb +43 -0
  32. data/lib/pact/doc/sort_interactions.rb +16 -0
  33. data/lib/pact/hal/authorization_header_redactor.rb +32 -0
  34. data/lib/pact/hal/entity.rb +110 -0
  35. data/lib/pact/hal/http_client.rb +128 -0
  36. data/lib/pact/hal/link.rb +112 -0
  37. data/lib/pact/hal/non_json_entity.rb +28 -0
  38. data/lib/pact/hash_refinements.rb +17 -0
  39. data/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb +112 -0
  40. data/lib/pact/pact_broker/fetch_pacts.rb +103 -0
  41. data/lib/pact/pact_broker/notices.rb +34 -0
  42. data/lib/pact/pact_broker/pact_selection_description.rb +66 -0
  43. data/lib/pact/pact_broker.rb +25 -0
  44. data/lib/pact/project_root.rb +7 -0
  45. data/lib/pact/provider/configuration/configuration_extension.rb +69 -0
  46. data/lib/pact/provider/configuration/dsl.rb +18 -0
  47. data/lib/pact/provider/configuration/message_provider_dsl.rb +63 -0
  48. data/lib/pact/provider/configuration/pact_verification.rb +48 -0
  49. data/lib/pact/provider/configuration/pact_verification_from_broker.rb +126 -0
  50. data/lib/pact/provider/configuration/service_provider_config.rb +32 -0
  51. data/lib/pact/provider/configuration/service_provider_dsl.rb +107 -0
  52. data/lib/pact/provider/configuration.rb +7 -0
  53. data/lib/pact/provider/context.rb +0 -0
  54. data/lib/pact/provider/help/console_text.rb +76 -0
  55. data/lib/pact/provider/help/content.rb +38 -0
  56. data/lib/pact/provider/help/pact_diff.rb +43 -0
  57. data/lib/pact/provider/help/prompt_text.rb +49 -0
  58. data/lib/pact/provider/help/write.rb +56 -0
  59. data/lib/pact/provider/matchers/messages.rb +66 -0
  60. data/lib/pact/provider/pact_helper_locator.rb +24 -0
  61. data/lib/pact/provider/pact_source.rb +40 -0
  62. data/lib/pact/provider/pact_spec_runner.rb +188 -0
  63. data/lib/pact/provider/pact_uri.rb +55 -0
  64. data/lib/pact/provider/pact_verification.rb +17 -0
  65. data/lib/pact/provider/print_missing_provider_states.rb +35 -0
  66. data/lib/pact/provider/request.rb +77 -0
  67. data/lib/pact/provider/rspec/backtrace_formatter.rb +43 -0
  68. data/lib/pact/provider/rspec/calculate_exit_code.rb +18 -0
  69. data/lib/pact/provider/rspec/custom_options_file +0 -0
  70. data/lib/pact/provider/rspec/formatter_rspec_2.rb +76 -0
  71. data/lib/pact/provider/rspec/formatter_rspec_3.rb +195 -0
  72. data/lib/pact/provider/rspec/json_formatter.rb +100 -0
  73. data/lib/pact/provider/rspec/matchers.rb +80 -0
  74. data/lib/pact/provider/rspec/pact_broker_formatter.rb +76 -0
  75. data/lib/pact/provider/rspec.rb +234 -0
  76. data/lib/pact/provider/state/provider_state.rb +180 -0
  77. data/lib/pact/provider/state/provider_state_configured_modules.rb +15 -0
  78. data/lib/pact/provider/state/provider_state_manager.rb +42 -0
  79. data/lib/pact/provider/state/provider_state_proxy.rb +39 -0
  80. data/lib/pact/provider/state/set_up.rb +13 -0
  81. data/lib/pact/provider/state/tear_down.rb +13 -0
  82. data/lib/pact/provider/test_methods.rb +77 -0
  83. data/lib/pact/provider/verification_report.rb +36 -0
  84. data/lib/pact/provider/verification_results/create.rb +88 -0
  85. data/lib/pact/provider/verification_results/publish.rb +143 -0
  86. data/lib/pact/provider/verification_results/publish_all.rb +50 -0
  87. data/lib/pact/provider/verification_results/verification_result.rb +40 -0
  88. data/lib/pact/provider/world.rb +50 -0
  89. data/lib/pact/provider.rb +3 -0
  90. data/lib/pact/retry.rb +37 -0
  91. data/lib/pact/tasks/task_helper.rb +62 -0
  92. data/lib/pact/tasks/verification_task.rb +95 -0
  93. data/lib/pact/tasks.rb +2 -0
  94. data/lib/pact/templates/help.erb +22 -0
  95. data/lib/pact/templates/provider_state.erb +14 -0
  96. data/lib/pact/utils/metrics.rb +100 -0
  97. data/lib/pact/utils/string.rb +35 -0
  98. data/lib/pact/v2/configuration.rb +23 -0
  99. data/lib/pact/v2/consumer/grpc_interaction_builder.rb +187 -0
  100. data/lib/pact/v2/consumer/http_interaction_builder.rb +163 -0
  101. data/lib/pact/v2/consumer/interaction_contents.rb +54 -0
  102. data/lib/pact/v2/consumer/message_interaction_builder.rb +280 -0
  103. data/lib/pact/v2/consumer/mock_server.rb +99 -0
  104. data/lib/pact/v2/consumer/pact_config/base.rb +24 -0
  105. data/lib/pact/v2/consumer/pact_config/grpc.rb +26 -0
  106. data/lib/pact/v2/consumer/pact_config/http.rb +55 -0
  107. data/lib/pact/v2/consumer/pact_config/message.rb +17 -0
  108. data/lib/pact/v2/consumer/pact_config.rb +24 -0
  109. data/lib/pact/v2/consumer.rb +8 -0
  110. data/lib/pact/v2/matchers/base.rb +67 -0
  111. data/lib/pact/v2/matchers/v1/equality.rb +19 -0
  112. data/lib/pact/v2/matchers/v2/regex.rb +19 -0
  113. data/lib/pact/v2/matchers/v2/type.rb +17 -0
  114. data/lib/pact/v2/matchers/v3/boolean.rb +17 -0
  115. data/lib/pact/v2/matchers/v3/date.rb +18 -0
  116. data/lib/pact/v2/matchers/v3/date_time.rb +18 -0
  117. data/lib/pact/v2/matchers/v3/decimal.rb +17 -0
  118. data/lib/pact/v2/matchers/v3/each.rb +42 -0
  119. data/lib/pact/v2/matchers/v3/include.rb +17 -0
  120. data/lib/pact/v2/matchers/v3/integer.rb +17 -0
  121. data/lib/pact/v2/matchers/v3/number.rb +17 -0
  122. data/lib/pact/v2/matchers/v3/time.rb +18 -0
  123. data/lib/pact/v2/matchers/v4/each_key.rb +26 -0
  124. data/lib/pact/v2/matchers/v4/each_key_value.rb +32 -0
  125. data/lib/pact/v2/matchers/v4/each_value.rb +33 -0
  126. data/lib/pact/v2/matchers/v4/not_empty.rb +17 -0
  127. data/lib/pact/v2/matchers.rb +94 -0
  128. data/lib/pact/v2/native/blocking_verifier.rb +17 -0
  129. data/lib/pact/v2/native/logger.rb +25 -0
  130. data/lib/pact/v2/provider/async_message_verifier.rb +28 -0
  131. data/lib/pact/v2/provider/base_verifier.rb +242 -0
  132. data/lib/pact/v2/provider/grpc_verifier.rb +38 -0
  133. data/lib/pact/v2/provider/gruf_server.rb +75 -0
  134. data/lib/pact/v2/provider/http_server.rb +79 -0
  135. data/lib/pact/v2/provider/http_verifier.rb +43 -0
  136. data/lib/pact/v2/provider/message_provider_servlet.rb +79 -0
  137. data/lib/pact/v2/provider/mixed_verifier.rb +22 -0
  138. data/lib/pact/v2/provider/pact_broker_proxy.rb +71 -0
  139. data/lib/pact/v2/provider/pact_broker_proxy_runner.rb +77 -0
  140. data/lib/pact/v2/provider/pact_config/async.rb +29 -0
  141. data/lib/pact/v2/provider/pact_config/base.rb +101 -0
  142. data/lib/pact/v2/provider/pact_config/grpc.rb +26 -0
  143. data/lib/pact/v2/provider/pact_config/http.rb +27 -0
  144. data/lib/pact/v2/provider/pact_config/mixed.rb +39 -0
  145. data/lib/pact/v2/provider/pact_config.rb +26 -0
  146. data/lib/pact/v2/provider/provider_server_runner.rb +89 -0
  147. data/lib/pact/v2/provider/provider_state_configuration.rb +32 -0
  148. data/lib/pact/v2/provider/provider_state_servlet.rb +86 -0
  149. data/lib/pact/v2/provider.rb +8 -0
  150. data/lib/pact/v2/railtie.rb +13 -0
  151. data/lib/pact/v2/rspec/support/pact_consumer_helpers.rb +80 -0
  152. data/lib/pact/v2/rspec/support/pact_message_helpers.rb +42 -0
  153. data/lib/pact/v2/rspec/support/pact_provider_helpers.rb +129 -0
  154. data/lib/pact/v2/rspec/support/waterdrop/pact_waterdrop_client.rb +27 -0
  155. data/lib/pact/v2/rspec/support/webmock/webmock_helpers.rb +30 -0
  156. data/lib/pact/v2/rspec.rb +17 -0
  157. data/lib/pact/v2/tasks/pact.rake +13 -0
  158. data/lib/pact/v2/version.rb +8 -0
  159. data/lib/pact/v2.rb +71 -0
  160. data/lib/pact/version.rb +4 -0
  161. data/lib/pact.rb +13 -0
  162. data/lib/tasks/pact.rake +34 -0
  163. data/pact.gemspec +106 -0
  164. 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