pact 1.41.2 → 1.53.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.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +219 -0
  3. data/lib/pact/cli/run_pact_verification.rb +23 -7
  4. data/lib/pact/cli/spec_criteria.rb +3 -0
  5. data/lib/pact/cli.rb +5 -0
  6. data/lib/pact/consumer/configuration/dsl.rb +0 -1
  7. data/lib/pact/consumer/consumer_contract_builder.rb +4 -0
  8. data/lib/pact/consumer/interaction_builder.rb +6 -0
  9. data/lib/pact/consumer/spec_hooks.rb +2 -2
  10. data/lib/pact/doc/sort_interactions.rb +2 -3
  11. data/lib/pact/hal/http_client.rb +11 -5
  12. data/lib/pact/hal/link.rb +50 -13
  13. data/lib/pact/hal/non_json_entity.rb +28 -0
  14. data/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb +93 -0
  15. data/lib/pact/pact_broker/notices.rb +34 -0
  16. data/lib/pact/pact_broker/pact_selection_description.rb +24 -0
  17. data/lib/pact/pact_broker.rb +10 -4
  18. data/lib/pact/provider/configuration/dsl.rb +6 -1
  19. data/lib/pact/provider/configuration/message_provider_dsl.rb +59 -0
  20. data/lib/pact/provider/configuration/pact_verification_from_broker.rb +28 -4
  21. data/lib/pact/provider/configuration/service_provider_dsl.rb +1 -1
  22. data/lib/pact/provider/help/content.rb +4 -4
  23. data/lib/pact/provider/help/pact_diff.rb +10 -34
  24. data/lib/pact/provider/help/write.rb +6 -7
  25. data/lib/pact/provider/pact_helper_locator.rb +0 -1
  26. data/lib/pact/provider/pact_source.rb +10 -1
  27. data/lib/pact/provider/pact_spec_runner.rb +24 -16
  28. data/lib/pact/provider/pact_uri.rb +8 -6
  29. data/lib/pact/provider/request.rb +1 -1
  30. data/lib/pact/provider/rspec/formatter_rspec_3.rb +21 -6
  31. data/lib/pact/provider/rspec/json_formatter.rb +100 -0
  32. data/lib/pact/provider/rspec/pact_broker_formatter.rb +1 -1
  33. data/lib/pact/provider/rspec.rb +17 -7
  34. data/lib/pact/provider/test_methods.rb +9 -3
  35. data/lib/pact/provider/verification_results/publish.rb +3 -0
  36. data/lib/pact/provider/verification_results/publish_all.rb +14 -1
  37. data/lib/pact/provider/verification_results/verification_result.rb +1 -4
  38. data/lib/pact/provider/world.rb +1 -1
  39. data/lib/pact/tasks/task_helper.rb +6 -1
  40. data/lib/pact/version.rb +1 -1
  41. data/pact.gemspec +11 -13
  42. metadata +59 -56
  43. data/lib/pact/pact_broker/fetch_pending_pacts.rb +0 -58
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 682d57626c30c4ce3f4e83038a3e5ff54d0f4878
4
- data.tar.gz: 7eb5834ea442abebf6e8739a5a2746514560fdc8
2
+ SHA256:
3
+ metadata.gz: 36cdbcc7291013248a5b691e8dec77f7153fd3c5c75d664e5da651943a8673dc
4
+ data.tar.gz: 0a75d19524d85f5623f6f8f9b042b1e481f551a5784cb2c48e86633f2d3d7329
5
5
  SHA512:
6
- metadata.gz: 369f376d001db7fac67ed5fce394dd0672c735de178c4c940b67082e7f36e7b8f43e18f2eb91d93403c969a1c26a995c229331f14780563e18b957456951b814
7
- data.tar.gz: db56fdd2c74f3cba9dd6b1e3ec7983eb50a46888f2c6ea7a9a70f2153738be1bbd6a53894a433d70d8f8dd4329b3526334b31c825cc7bcf75d4072e962f4f506
6
+ metadata.gz: faa46bb073cdacca555022ee518d15e13182f286f1b6d75f309f7f5d6d6692674c046ced1d3b8598d10772b7dc25d3157aa556d6ac47453753dc90607ed8575b
7
+ data.tar.gz: 360a99577f6925e21ab6ce0949bca79a3309c1a16e7dbd21ae72fe20b7c46a87eca0f422d810061d2adc594141b76ca4be831eeb8859aff29eca00fe9227f78e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,222 @@
1
+ <a name="v1.53.0"></a>
2
+ ### v1.53.0 (2020-09-11)
3
+
4
+ #### Features
5
+
6
+ * add support for the enable_pending flag ([16866f4](/../../commit/16866f4))
7
+
8
+ <a name="v1.52.0"></a>
9
+ ### v1.52.0 (2020-09-10)
10
+
11
+ #### Features
12
+
13
+ * support webdav http methods ([fa1d712](/../../commit/fa1d712))
14
+
15
+ <a name="v1.51.1"></a>
16
+ ### v1.51.1 (2020-08-12)
17
+
18
+ #### Bug Fixes
19
+
20
+ * update thor dependency (#218) ([bf3ce69](/../../commit/bf3ce69))
21
+ * bump rake dependency per CVE-2020-8130 (#219) ([09feaa6](/../../commit/09feaa6))
22
+
23
+ <a name="v1.51.0"></a>
24
+ ### v1.51.0 (2020-06-24)
25
+
26
+
27
+ #### Features
28
+
29
+ * allow individual interactions to be re-run by setting PACT_BROKER_INTERACTION_ID ([a586d80](/../../commit/a586d80))
30
+
31
+
32
+ <a name="v1.50.1"></a>
33
+ ### v1.50.1 (2020-06-15)
34
+
35
+
36
+ #### Bug Fixes
37
+
38
+ * fix integration with pact-message-ruby (#216) ([d2da13e](/../../commit/d2da13e))
39
+
40
+
41
+ <a name="v1.50.0"></a>
42
+ ### v1.50.0 (2020-04-25)
43
+
44
+
45
+ #### Features
46
+
47
+ * Set expected interactions on mock service but without writing them to pact file (#210) ([14f5327](/../../commit/14f5327))
48
+
49
+
50
+ <a name="v1.49.3"></a>
51
+ ### v1.49.3 (2020-04-22)
52
+
53
+
54
+ #### Bug Fixes
55
+
56
+ * pact selection verification options logging ([9ff59f4](/../../commit/9ff59f4))
57
+
58
+
59
+ <a name="v1.49.2"></a>
60
+ ### v1.49.2 (2020-04-08)
61
+
62
+
63
+ #### Bug Fixes
64
+
65
+ * json parser error for top level JSON values ([dafbc35](/../../commit/dafbc35))
66
+
67
+
68
+ <a name="v1.49.1"></a>
69
+ ### v1.49.1 (2020-03-21)
70
+
71
+
72
+ #### Bug Fixes
73
+
74
+ * ensure diff is included in the json output ([0bd9753](/../../commit/0bd9753))
75
+ * ensure the presence of basic auth credentials does not cause an error when displaying the path of a pact on the local filesystem ([f6a0b4d](/../../commit/f6a0b4d))
76
+
77
+
78
+ <a name="v1.49.0"></a>
79
+ ### v1.49.0 (2020-02-18)
80
+
81
+
82
+ #### Features
83
+
84
+ * use environment variables PACT_BROKER_USERNAME and PACT_BROKER_PASSWORD when verifying a pact by URL, if the environment variables are present ([308f25d](/../../commit/308f25d))
85
+
86
+
87
+ <a name="v1.48.0"></a>
88
+ ### v1.48.0 (2020-02-13)
89
+
90
+
91
+ #### Features
92
+
93
+ * use certificates from SSL_CERT_FILE and SSL_CERT_DIR environment variables in HTTP connections ([164912b](/../../commit/164912b))
94
+
95
+
96
+ <a name="v1.47.0"></a>
97
+ ### v1.47.0 (2020-02-08)
98
+
99
+
100
+ #### Features
101
+
102
+ * update json formatter output ([376e47a](/../../commit/376e47a))
103
+ * add pact metadata to json formatter ([6c6ddb8](/../../commit/6c6ddb8))
104
+
105
+
106
+ <a name="v1.46.1"></a>
107
+ ### v1.46.1 (2020-01-22)
108
+
109
+
110
+ #### Bug Fixes
111
+
112
+ * send output messages to the correct stream when using the XML formatter ([e768a33](/../../commit/e768a33))
113
+
114
+
115
+ <a name="v1.46.0"></a>
116
+ ### v1.46.0 (2020-01-22)
117
+
118
+
119
+ #### Features
120
+
121
+ * expose full notice object in JSON output ([bdc2711](/../../commit/bdc2711))
122
+
123
+
124
+ #### Bug Fixes
125
+
126
+ * remove accidentally committed verbose: true ([498518c](/../../commit/498518c))
127
+
128
+
129
+ <a name="v1.45.0"></a>
130
+ ### v1.45.0 (2020-01-21)
131
+
132
+
133
+ #### Features
134
+
135
+ * use custom json formatter when --format json is specified and send it straight to stdout or the configured file ([6c703a1](/../../commit/6c703a1))
136
+ * support pending pacts in json formatter ([2c0d20d](/../../commit/2c0d20d))
137
+
138
+
139
+ #### Bug Fixes
140
+
141
+ * show pending test output in yellow instead of red ([e8d4a55](/../../commit/e8d4a55))
142
+
143
+
144
+ <a name="v1.44.1"></a>
145
+ ### v1.44.1 (2020-01-20)
146
+
147
+
148
+ #### Bug Fixes
149
+
150
+ * print notices from 'pacts for verification' response to indicate why pacts are included an/or pending ([b107348](/../../commit/b107348))
151
+
152
+
153
+ <a name="v1.44.0"></a>
154
+ ### v1.44.0 (2020-01-16)
155
+
156
+
157
+ #### Features
158
+
159
+ * **message pact**
160
+ * add DSL for configuring Message Pact verifications ([a5181b6](/../../commit/a5181b6))
161
+
162
+
163
+ <a name="v1.43.1"></a>
164
+ ### v1.43.1 (2020-01-11)
165
+
166
+
167
+ #### Bug Fixes
168
+
169
+ * use configured credentials when fetching the diff with previous version ([b9deb09](/../../commit/b9deb09))
170
+ * use URI.open instead of Kernel.open ([7b3ea81](/../../commit/7b3ea81))
171
+
172
+
173
+ <a name="v1.43.0"></a>
174
+ ### v1.43.0 (2020-01-11)
175
+
176
+
177
+ #### Features
178
+
179
+ * **verify**
180
+ * allow includePendingStatus to be specified when fetching pacts ([1f5fc9c](/../../commit/1f5fc9c))
181
+
182
+
183
+ <a name="v1.42.3"></a>
184
+ ### v1.42.3 (2019-11-15)
185
+
186
+
187
+ #### Bug Fixes
188
+
189
+ * **verify**
190
+ * exit with status 0 if all pacts are in pending state ([2f7110b](/../../commit/2f7110b))
191
+
192
+
193
+ <a name="v1.42.2"></a>
194
+ ### v1.42.2 (2019-11-09)
195
+
196
+
197
+ #### Bug Fixes
198
+
199
+ * remove missed &. ([be700d8](/../../commit/be700d8))
200
+
201
+
202
+ <a name="v1.42.1"></a>
203
+ ### v1.42.1 (2019-11-09)
204
+
205
+
206
+ #### Bug Fixes
207
+
208
+ * can't use safe navigation operator because of Ruby 2.2 in Travelling Ruby for the pact-ruby-standalone ([3068ceb](/../../commit/3068ceb))
209
+
210
+
211
+ <a name="v1.42.0"></a>
212
+ ### v1.42.0 (2019-09-26)
213
+
214
+
215
+ #### Features
216
+
217
+ * use new 'pacts for verification' endpoint to retrieve pacts (#199) ([55bb935](/../../commit/55bb935))
218
+
219
+
1
220
  <a name="v1.41.2"></a>
2
221
  ### v1.41.2 (2019-09-10)
3
222
 
@@ -3,7 +3,6 @@ require 'pact/cli/spec_criteria'
3
3
  module Pact
4
4
  module Cli
5
5
  class RunPactVerification
6
-
7
6
  attr_reader :options
8
7
 
9
8
  def initialize options
@@ -15,6 +14,7 @@ module Pact
15
14
  end
16
15
 
17
16
  def call
17
+ configure_output
18
18
  initialize_rspec
19
19
  setup_load_path
20
20
  load_pact_helper
@@ -44,24 +44,32 @@ module Pact
44
44
  end
45
45
 
46
46
  def run_specs
47
- exit_code = if options[:pact_uri]
48
- run_with_pact_uri
47
+ exit_code = if options[:pact_uri].is_a?(String)
48
+ run_with_pact_url_string
49
+ elsif options[:pact_uri]
50
+ run_with_pact_uri_object # from pact-provider-verifier
49
51
  else
50
- run_with_configured_pacts
52
+ run_with_configured_pacts_from_pact_helper
51
53
  end
52
54
  exit exit_code
53
55
  end
54
56
 
55
- def run_with_pact_uri
57
+ def run_with_pact_url_string
56
58
  pact_repository_uri_options = {}
59
+ pact_repository_uri_options[:username] = ENV['PACT_BROKER_USERNAME'] if ENV['PACT_BROKER_USERNAME']
60
+ pact_repository_uri_options[:password] = ENV['PACT_BROKER_PASSWORD'] if ENV['PACT_BROKER_PASSWORD']
61
+ pact_repository_uri_options[:token] = ENV['PACT_BROKER_TOKEN']
57
62
  pact_repository_uri_options[:username] = options[:pact_broker_username] if options[:pact_broker_username]
58
63
  pact_repository_uri_options[:password] = options[:pact_broker_password] if options[:pact_broker_password]
59
- pact_repository_uri_options[:token] = ENV['PACT_BROKER_TOKEN']
60
64
  pact_uri = ::Pact::Provider::PactURI.new(options[:pact_uri], pact_repository_uri_options)
61
65
  Pact::Provider::PactSpecRunner.new([pact_uri], pact_spec_options).run
62
66
  end
63
67
 
64
- def run_with_configured_pacts
68
+ def run_with_pact_uri_object
69
+ Pact::Provider::PactSpecRunner.new([options[:pact_uri]], pact_spec_options).run
70
+ end
71
+
72
+ def run_with_configured_pacts_from_pact_helper
65
73
  pact_urls = Pact.provider_world.pact_urls
66
74
  raise "Please configure a pact to verify" if pact_urls.empty?
67
75
  Pact::Provider::PactSpecRunner.new(pact_urls, pact_spec_options).run
@@ -77,6 +85,14 @@ module Pact
77
85
  request_customizer: options[:request_customizer]
78
86
  }
79
87
  end
88
+
89
+ def configure_output
90
+ if options[:format] == 'json' && !options[:out]
91
+ # Don't want to mess up the JSON parsing with messages to stdout, so send it to stderr
92
+ require 'pact/configuration'
93
+ Pact.configuration.output_stream = Pact.configuration.error_stream
94
+ end
95
+ end
80
96
  end
81
97
  end
82
98
  end
@@ -6,8 +6,11 @@ module Pact
6
6
  criteria = {}
7
7
 
8
8
  criteria[:description] = Regexp.new(options[:description]) if options[:description]
9
+ criteria[:_id] = options[:pact_broker_interaction_id] if options[:pact_broker_interaction_id]
10
+ criteria[:index] = options[:interaction_index] if options[:interaction_index]
9
11
 
10
12
  provider_state = options[:provider_state]
13
+
11
14
  if provider_state
12
15
  if provider_state.length == 0
13
16
  criteria[:provider_state] = nil #Allow PACT_PROVIDER_STATE="" to mean no provider state
data/lib/pact/cli.rb CHANGED
@@ -4,6 +4,9 @@ require 'pact/provider/configuration'
4
4
 
5
5
  module Pact
6
6
  class CLI < Thor
7
+ def self.exit_on_failure? # Thor 1.0 deprecation guard
8
+ false
9
+ end
7
10
 
8
11
  desc 'verify', "Verify a pact"
9
12
  method_option :pact_helper, aliases: "-h", desc: "Pact helper file", :required => true
@@ -18,6 +21,8 @@ module Pact
18
21
  default: Pact.configuration.interactions_replay_order
19
22
  method_option :description, aliases: "-d", desc: "Interaction description filter"
20
23
  method_option :provider_state, aliases: "-s", desc: "Provider state filter"
24
+ method_option :interaction_index, type: :numeric, desc: "Index filter"
25
+ method_option :pact_broker_interaction_id, desc: "Pact Broker interaction ID filter"
21
26
  method_option :format, aliases: "-f", banner: "FORMATTER", desc: "RSpec formatter. Defaults to custom Pact formatter. [j]son may also be used."
22
27
  method_option :out, aliases: "-o", banner: "FILE", desc: "Write output to a file instead of $stdout."
23
28
 
@@ -1,7 +1,6 @@
1
1
  require 'pact/consumer/configuration/service_consumer'
2
2
 
3
3
  module Pact
4
-
5
4
  module Consumer
6
5
  module DSL
7
6
  def service_consumer name, &block
@@ -25,6 +25,10 @@ module Pact
25
25
  @mock_service_base_url = "http://#{attributes[:host]}:#{attributes[:port]}"
26
26
  end
27
27
 
28
+ def without_writing_to_pact
29
+ interaction_builder.without_writing_to_pact
30
+ end
31
+
28
32
  def given(provider_state)
29
33
  interaction_builder.given(provider_state)
30
34
  end
@@ -13,6 +13,12 @@ module Pact
13
13
  @callback = block
14
14
  end
15
15
 
16
+ def without_writing_to_pact
17
+ interaction.metadata ||= {}
18
+ interaction.metadata[:write_to_pact] = false
19
+ self
20
+ end
21
+
16
22
  def upon_receiving description
17
23
  @interaction.description = description
18
24
  self
@@ -29,7 +29,7 @@ module Pact
29
29
 
30
30
  def after_suite
31
31
  if Pact.consumer_world.any_pact_examples_ran?
32
- Pact.consumer_world.consumer_contract_builders.each { | c | c.write_pact }
32
+ Pact.consumer_world.consumer_contract_builders.each(&:write_pact)
33
33
  Pact::Doc::Generate.call
34
34
  Pact::MockService::AppManager.instance.kill_all
35
35
  Pact::MockService::AppManager.instance.clear_all
@@ -37,4 +37,4 @@ module Pact
37
37
  end
38
38
  end
39
39
  end
40
- end
40
+ end
@@ -3,7 +3,7 @@ module Pact
3
3
  class SortInteractions
4
4
 
5
5
  def self.call interactions
6
- interactions.sort{|a, b| sortable_id(a) <=> sortable_id(b)}
6
+ interactions.sort_by { |interaction| sortable_id(interaction) }
7
7
  end
8
8
 
9
9
  private
@@ -11,7 +11,6 @@ module Pact
11
11
  def self.sortable_id interaction
12
12
  "#{interaction.description.downcase} #{interaction.response.status} #{(interaction.provider_state || '').downcase}"
13
13
  end
14
-
15
14
  end
16
15
  end
17
- end
16
+ end
@@ -1,6 +1,7 @@
1
1
  require 'pact/retry'
2
2
  require 'pact/hal/authorization_header_redactor'
3
3
  require 'net/http'
4
+ require 'rack'
4
5
 
5
6
  module Pact
6
7
  module Hal
@@ -15,9 +16,11 @@ module Pact
15
16
  end
16
17
 
17
18
  def get href, params = {}, headers = {}
18
- query = params.collect{ |(key, value)| "#{CGI::escape(key)}=#{CGI::escape(value)}" }.join("&")
19
19
  uri = URI(href)
20
- uri.query = query
20
+ if params && params.any?
21
+ existing_params = Rack::Utils.parse_nested_query(uri.query)
22
+ uri.query = Rack::Utils.build_nested_query(existing_params.merge(params))
23
+ end
21
24
  perform_request(create_request(uri, 'Get', nil, headers), uri)
22
25
  end
23
26
 
@@ -33,12 +36,9 @@ module Pact
33
36
 
34
37
  def create_request uri, http_method, body = nil, headers = {}
35
38
  request = Net::HTTP.const_get(http_method).new(uri.request_uri)
36
- request['Content-Type'] = "application/json" if ['Post', 'Put', 'Patch'].include?(http_method)
37
- request['Accept'] = "application/hal+json"
38
39
  headers.each do | key, value |
39
40
  request[key] = value
40
41
  end
41
-
42
42
  request.body = body if body
43
43
  request.basic_auth username, password if username
44
44
  request['Authorization'] = "Bearer #{token}" if token
@@ -50,6 +50,8 @@ module Pact
50
50
  http = Net::HTTP.new(uri.host, uri.port, :ENV)
51
51
  http.set_debug_output(output_stream) if verbose
52
52
  http.use_ssl = (uri.scheme == 'https')
53
+ http.ca_file = ENV['SSL_CERT_FILE'] if ENV['SSL_CERT_FILE'] && ENV['SSL_CERT_FILE'] != ''
54
+ http.ca_path = ENV['SSL_CERT_DIR'] if ENV['SSL_CERT_DIR'] && ENV['SSL_CERT_DIR'] != ''
53
55
  http.start do |http|
54
56
  http.request request
55
57
  end
@@ -82,6 +84,10 @@ module Pact
82
84
  def success?
83
85
  __getobj__().code.start_with?("2")
84
86
  end
87
+
88
+ def json?
89
+ self['content-type'] && self['content-type'] =~ /json/
90
+ end
85
91
  end
86
92
  end
87
93
  end
data/lib/pact/hal/link.rb CHANGED
@@ -6,6 +6,15 @@ module Pact
6
6
  class Link
7
7
  attr_reader :request_method, :href
8
8
 
9
+ DEFAULT_GET_HEADERS = {
10
+ "Accept" => "application/hal+json"
11
+ }.freeze
12
+
13
+ DEFAULT_POST_HEADERS = {
14
+ "Accept" => "application/hal+json",
15
+ "Content-Type" => "application/json"
16
+ }.freeze
17
+
9
18
  def initialize(attrs, http_client)
10
19
  @attrs = attrs
11
20
  @request_method = attrs.fetch(:method, :get).to_sym
@@ -14,14 +23,14 @@ module Pact
14
23
  end
15
24
 
16
25
  def run(payload = nil)
17
- response = case request_method
18
- when :get
19
- get(payload)
20
- when :put
21
- put(payload)
22
- when :post
23
- post(payload)
24
- end
26
+ case request_method
27
+ when :get
28
+ get(payload)
29
+ when :put
30
+ put(payload)
31
+ when :post
32
+ post(payload)
33
+ end
25
34
  end
26
35
 
27
36
  def title_or_name
@@ -37,29 +46,57 @@ module Pact
37
46
  end
38
47
 
39
48
  def get(payload = {}, headers = {})
40
- wrap_response(href, @http_client.get(href, payload, headers))
49
+ wrap_response(href, @http_client.get(href, payload, DEFAULT_GET_HEADERS.merge(headers)))
50
+ end
51
+
52
+ def get!(*args)
53
+ get(*args).assert_success!
41
54
  end
42
55
 
43
56
  def put(payload = nil, headers = {})
44
- wrap_response(href, @http_client.put(href, payload ? payload.to_json : nil, headers))
57
+ wrap_response(href, @http_client.put(href, payload ? payload.to_json : nil, DEFAULT_POST_HEADERS.merge(headers)))
45
58
  end
46
59
 
47
60
  def post(payload = nil, headers = {})
48
- wrap_response(href, @http_client.post(href, payload ? payload.to_json : nil, headers))
61
+ wrap_response(href, @http_client.post(href, payload ? payload.to_json : nil, DEFAULT_POST_HEADERS.merge(headers)))
62
+ end
63
+
64
+ def post!(payload = nil, headers = {})
65
+ post(payload, headers).assert_success!
49
66
  end
50
67
 
51
68
  def expand(params)
52
69
  expanded_url = expand_url(params, href)
53
70
  new_attrs = @attrs.merge('href' => expanded_url)
54
- Link.new(new_attrs, @http_client)
71
+ Link.new(new_attrs, http_client)
72
+ end
73
+
74
+ def with_query(query)
75
+ if query && query.any?
76
+ uri = URI(href)
77
+ existing_query_params = Rack::Utils.parse_nested_query(uri.query)
78
+ uri.query = Rack::Utils.build_nested_query(existing_query_params.merge(query))
79
+ new_attrs = attrs.merge('href' => uri.to_s)
80
+ Link.new(new_attrs, http_client)
81
+ else
82
+ self
83
+ end
55
84
  end
56
85
 
57
86
  private
58
87
 
88
+ attr_reader :attrs, :http_client
89
+
59
90
  def wrap_response(href, http_response)
60
91
  require 'pact/hal/entity' # avoid circular reference
92
+ require 'pact/hal/non_json_entity'
93
+
61
94
  if http_response.success?
62
- Entity.new(href, http_response.body, @http_client, http_response)
95
+ if http_response.json?
96
+ Entity.new(href, http_response.body, @http_client, http_response)
97
+ else
98
+ NonJsonEntity.new(href, http_response.raw_body, @http_client, http_response)
99
+ end
63
100
  else
64
101
  ErrorEntity.new(href, http_response.raw_body, @http_client, http_response)
65
102
  end
@@ -0,0 +1,28 @@
1
+ module Pact
2
+ module Hal
3
+ class NonJsonEntity
4
+ def initialize(href, body, http_client, response = nil)
5
+ @href = href
6
+ @body = body
7
+ @client = http_client
8
+ @response = response
9
+ end
10
+
11
+ def success?
12
+ true
13
+ end
14
+
15
+ def response
16
+ @response
17
+ end
18
+
19
+ def body
20
+ @body
21
+ end
22
+
23
+ def assert_success!
24
+ self
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,93 @@
1
+ require 'pact/hal/entity'
2
+ require 'pact/hal/http_client'
3
+ require 'pact/provider/pact_uri'
4
+ require 'pact/errors'
5
+ require 'pact/pact_broker/fetch_pacts'
6
+ require 'pact/pact_broker/notices'
7
+ require 'pact/pact_broker/pact_selection_description'
8
+
9
+ module Pact
10
+ module PactBroker
11
+ class FetchPactURIsForVerification
12
+ include PactSelectionDescription
13
+ attr_reader :provider, :consumer_version_selectors, :provider_version_tags, :broker_base_url, :http_client_options, :http_client, :options
14
+
15
+ PACTS_FOR_VERIFICATION_RELATION = 'beta:provider-pacts-for-verification'.freeze
16
+ PACTS = 'pacts'.freeze
17
+ HREF = 'href'.freeze
18
+ LINKS = '_links'.freeze
19
+ SELF = 'self'.freeze
20
+ EMBEDDED = '_embedded'.freeze
21
+
22
+ def initialize(provider, consumer_version_selectors, provider_version_tags, broker_base_url, http_client_options, options = {})
23
+ @provider = provider
24
+ @consumer_version_selectors = consumer_version_selectors || []
25
+ @provider_version_tags = [*provider_version_tags]
26
+ @http_client_options = http_client_options
27
+ @broker_base_url = broker_base_url
28
+ @http_client = Pact::Hal::HttpClient.new(http_client_options)
29
+ @options = options
30
+ end
31
+
32
+ def self.call(provider, consumer_version_selectors, provider_version_tags, broker_base_url, http_client_options, options = {})
33
+ new(provider, consumer_version_selectors, provider_version_tags, broker_base_url, http_client_options, options).call
34
+ end
35
+
36
+ def call
37
+ if index.can?(PACTS_FOR_VERIFICATION_RELATION)
38
+ log_message
39
+ pacts_for_verification
40
+ else
41
+ # Fall back to old method of fetching pacts
42
+ consumer_version_tags = consumer_version_selectors.collect{ | selector | selector[:tag] }
43
+ FetchPacts.call(provider, consumer_version_tags, broker_base_url, http_client_options)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def index
50
+ @index_entity ||= Pact::Hal::Link.new({ "href" => broker_base_url }, http_client).get.assert_success!
51
+ end
52
+
53
+ def pacts_for_verification
54
+ pacts_for_verification_entity.response.body[EMBEDDED][PACTS].collect do | pact |
55
+ metadata = {
56
+ pending: pact["verificationProperties"]["pending"],
57
+ notices: extract_notices(pact),
58
+ short_description: pact["shortDescription"]
59
+ }
60
+ Pact::Provider::PactURI.new(pact[LINKS][SELF][HREF], http_client_options, metadata)
61
+ end
62
+ end
63
+
64
+ def pacts_for_verification_entity
65
+ index
66
+ ._link(PACTS_FOR_VERIFICATION_RELATION)
67
+ .expand(provider: provider)
68
+ .post!(query)
69
+ end
70
+
71
+ def query
72
+ q = {}
73
+ q["includePendingStatus"] = true if options[:include_pending_status]
74
+ q["consumerVersionSelectors"] = consumer_version_selectors if consumer_version_selectors.any?
75
+ q["providerVersionTags"] = provider_version_tags if provider_version_tags.any?
76
+ q["includeWipPactsSince"] = options[:include_wip_pacts_since] if options[:include_wip_pacts_since]
77
+ q
78
+ end
79
+
80
+ def extract_notices(pact)
81
+ Notices.new((pact["verificationProperties"]["notices"] || []).collect{ |notice| symbolize_keys(notice) })
82
+ end
83
+
84
+ def symbolize_keys(hash)
85
+ hash.each_with_object({}){ |(k,v), h| h[k.to_sym] = v }
86
+ end
87
+
88
+ def log_message
89
+ Pact.configuration.output_stream.puts "INFO: #{pact_selection_description(provider, consumer_version_selectors, options, broker_base_url)}"
90
+ end
91
+ end
92
+ end
93
+ end