pact-support 1.16.4 → 1.16.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c13a4b7ad88f078970d7e0991fc8e7406a20267b038d67b3c583003b3b18814e
4
- data.tar.gz: f72c487f5e7f11a5d6db48812028130487d0a0d4a9ac1f8c2726bf5d8d487d4c
3
+ metadata.gz: 03a46a4e6bb3335f9acc353c80f485bd22d92e6b137e85fd25559a141eb282da
4
+ data.tar.gz: 967af721b125b04d725e5743a6759c6215b3b2af5e99526b9bbcfdf019ae0f05
5
5
  SHA512:
6
- metadata.gz: 985481757b4ec8880946efceb5929aceb818defcd80233ef908ed0cb8f55ed4e8ceb6c9f6e89cee4856dd581fd42dca4b6dc1d244dc9dece6a51fffe456c6915
7
- data.tar.gz: 8c5bfdc029b6461fb80a64089ef1d003f3dc0f93d2677020c37f9bd733423e1e976058f14199b2d8dcc36e5a648450d786d91a6fb215dbef0aab1e453c56d52a
6
+ metadata.gz: ee9efbb1051d9064ffe0079711885e56b90c14e01868d8afbb5a9b08bd85ca42f89226f805a61c44f6d565ba61157250b36dbc742722bb859af2789de21b0292
7
+ data.tar.gz: bff0e437c5392f0ead03eba3d0932ac71eea1a1fd44f6add3f68a3df023092bca101a465fc16c13f633efb9f1eb19c336705161d67aaac9dfff116b191fe5546
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ <a name="v1.16.8"></a>
2
+ ### v1.16.8 (2021-07-27)
3
+
4
+ #### Bug Fixes
5
+
6
+ * log HTTP request for pacts retrieved by URL when requested with verbose=true ([3288b81](/../../commit/3288b81))
7
+
8
+ <a name="v1.16.7"></a>
9
+ ### v1.16.7 (2021-01-28)
10
+
11
+ #### Bug Fixes
12
+
13
+ * dynamically parse actual query to match expected format ([a86a3e3](/../../commit/a86a3e3))
14
+
15
+ <a name="v1.16.6"></a>
16
+ ### v1.16.6 (2021-01-28)
17
+
18
+ #### Bug Fixes
19
+
20
+ * raise Pact::Error not RuntimeError when invalid constructor arguments are supplied to a Pact::Term ([d9fb8ea](/../../commit/d9fb8ea))
21
+ * update active support support for Ruby 3.0 ([6c30d42](/../../commit/6c30d42))
22
+
23
+ <a name="v1.16.5"></a>
24
+ ### v1.16.5 (2020-11-25)
25
+
26
+ #### Bug Fixes
27
+
28
+ * maintain the original string query for the provider verification while also parsing the string query into a hash to allow the matching rules to be applied correctly for use in the mock service on the consumer side ([12105dd](/../../commit/12105dd))
29
+
1
30
  <a name="v1.16.4"></a>
2
31
  ### v1.16.4 (2020-11-13)
3
32
 
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Pact Support
2
2
 
3
- [![Build Status](https://travis-ci.org/pact-foundation/pact-support.svg?branch=master)](https://travis-ci.org/pact-foundation/pact-support)
3
+ ![Build status](https://github.com/pact-foundation/pact-support/workflows/Test/badge.svg)
4
4
 
5
5
  Provides shared code for the Pact gems
@@ -23,12 +23,22 @@ module Pact
23
23
  end
24
24
 
25
25
  def self.parse_request request_hash, options
26
- if request_hash['query'].is_a?(String)
26
+ original_query_string = request_hash['query']
27
+ query_is_string = original_query_string.is_a?(String)
28
+ if query_is_string
27
29
  request_hash = request_hash.dup
28
30
  request_hash['query'] = Pact::Query.parse_string(request_hash['query'])
29
31
  end
32
+ # The query has to be a hash at this stage for the matching rules to be applied
30
33
  request_hash = Pact::MatchingRules.merge(request_hash, request_hash['matchingRules'], options)
31
- Pact::Request::Expected.from_hash(request_hash)
34
+ # The original query string needs to be passed in to the constructor so it can be used
35
+ # when the request is replayed. Otherwise, we loose the square brackets because they get lost
36
+ # in the translation between string => structured object, as we don't know/store which
37
+ # query string convention was used.
38
+ if query_is_string
39
+ request_hash['query'] = Pact::QueryHash.new(request_hash['query'], original_query_string, Pact::Query.parsed_as_nested?(request_hash['query']))
40
+ end
41
+ request = Pact::Request::Expected.from_hash(request_hash)
32
42
  end
33
43
 
34
44
  def self.parse_response response_hash, options
@@ -1,4 +1,6 @@
1
- require 'net/http'
1
+ require "net/http"
2
+ require "pact/configuration"
3
+ require "pact/http/authorization_header_redactor"
2
4
 
3
5
  module Pact
4
6
  module PactFile
@@ -81,7 +83,7 @@ module Pact
81
83
  request = Net::HTTP::Get.new(uri)
82
84
  request = prepare_auth(request, options) if options[:username] || options[:token]
83
85
 
84
- http = prepare_request(uri)
86
+ http = prepare_request(uri, options)
85
87
  response = perform_http_request(http, request, options)
86
88
 
87
89
  if response.is_a?(Net::HTTPRedirection)
@@ -89,7 +91,7 @@ module Pact
89
91
  req = Net::HTTP::Get.new(uri)
90
92
  req = prepare_auth(req, options) if options[:username] || options[:token]
91
93
 
92
- http = prepare_request(uri)
94
+ http = prepare_request(uri, options)
93
95
  response = perform_http_request(http, req, options)
94
96
  end
95
97
  response
@@ -101,11 +103,12 @@ module Pact
101
103
  request
102
104
  end
103
105
 
104
- def prepare_request(uri)
106
+ def prepare_request(uri, options)
105
107
  http = Net::HTTP.new(uri.host, uri.port, :ENV)
106
108
  http.use_ssl = (uri.scheme == 'https')
107
109
  http.ca_file = ENV['SSL_CERT_FILE'] if ENV['SSL_CERT_FILE'] && ENV['SSL_CERT_FILE'] != ''
108
110
  http.ca_path = ENV['SSL_CERT_DIR'] if ENV['SSL_CERT_DIR'] && ENV['SSL_CERT_DIR'] != ''
111
+ http.set_debug_output(Pact::Http::AuthorizationHeaderRedactor.new(Pact.configuration.output_stream)) if options[:verbose]
109
112
  http
110
113
  end
111
114
 
@@ -6,6 +6,8 @@ module Pact
6
6
  DEFAULT_SEP = /[&;] */n
7
7
  COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n }
8
8
 
9
+ class NestedQuery < Hash; end
10
+
9
11
  def self.create query
10
12
  if query.is_a? Hash
11
13
  Pact::QueryHash.new(query)
@@ -14,12 +16,20 @@ module Pact
14
16
  end
15
17
  end
16
18
 
19
+ def self.is_a_query_object?(object)
20
+ object.is_a?(Pact::QueryHash) || object.is_a?(Pact::QueryString)
21
+ end
22
+
23
+ def self.parsed_as_nested?(object)
24
+ object.is_a?(NestedQuery)
25
+ end
26
+
17
27
  def self.parse_string query_string
18
- parsed_query = parse_query(query_string)
28
+ parsed_query = parse_string_as_non_nested_query(query_string)
19
29
 
20
30
  # If Rails nested params...
21
31
  if parsed_query.keys.any?{ | key| key =~ /\[.*\]/ }
22
- parse_nested_query(query_string)
32
+ parse_string_as_nested_query(query_string)
23
33
  else
24
34
  parsed_query.each_with_object({}) do | (key, value), new_hash |
25
35
  new_hash[key] = [*value]
@@ -29,7 +39,7 @@ module Pact
29
39
 
30
40
  # Ripped from Rack to avoid adding an unnecessary dependency, thank you Rack
31
41
  # https://github.com/rack/rack/blob/649c72bab9e7b50d657b5b432d0c205c95c2be07/lib/rack/utils.rb
32
- def self.parse_query(qs, d = nil, &unescaper)
42
+ def self.parse_string_as_non_nested_query(qs, d = nil, &unescaper)
33
43
  unescaper ||= method(:unescape)
34
44
 
35
45
  params = {}
@@ -52,7 +62,7 @@ module Pact
52
62
  return params.to_h
53
63
  end
54
64
 
55
- def self.parse_nested_query(qs, d = nil)
65
+ def self.parse_string_as_nested_query(qs, d = nil)
56
66
  params = {}
57
67
 
58
68
  unless qs.nil? || qs.empty?
@@ -63,7 +73,7 @@ module Pact
63
73
  end
64
74
  end
65
75
 
66
- return params.to_h
76
+ return NestedQuery[params.to_h]
67
77
  end
68
78
 
69
79
  def self.normalize_params(params, name, v)
@@ -8,8 +8,20 @@ module Pact
8
8
  include ActiveSupportSupport
9
9
  include SymbolizeKeys
10
10
 
11
- def initialize(query)
11
+ attr_reader :original_string
12
+
13
+ def initialize(query, original_string = nil, nested = false)
12
14
  @hash = query.nil? ? query : convert_to_hash_of_arrays(query)
15
+ @original_string = original_string
16
+ @nested = nested
17
+ end
18
+
19
+ def nested?
20
+ @nested
21
+ end
22
+
23
+ def any_key_contains_square_brackets?
24
+ query.keys.any?{ |key| key =~ /\[.*\]/ }
13
25
  end
14
26
 
15
27
  def as_json(opts = {})
@@ -32,7 +44,14 @@ module Pact
32
44
  # from the actual query string.
33
45
  def difference(other)
34
46
  require 'pact/matchers' # avoid recursive loop between this file, pact/reification and pact/matchers
35
- Pact::Matchers.diff(query, symbolize_keys(convert_to_hash_of_arrays(Query.parse_string(other.query))), allow_unexpected_keys: false)
47
+
48
+ if any_key_contains_square_brackets?
49
+ other_query_hash_non_nested = Query.parse_string_as_non_nested_query(other.query)
50
+ Pact::Matchers.diff(query, convert_to_hash_of_arrays(other_query_hash_non_nested), allow_unexpected_keys: false)
51
+ else
52
+ other_query_hash = Query.parse_string(other.query)
53
+ Pact::Matchers.diff(query, symbolize_keys(convert_to_hash_of_arrays(other_query_hash)), allow_unexpected_keys: false)
54
+ end
36
55
  end
37
56
 
38
57
  def query
@@ -0,0 +1,32 @@
1
+ require "delegate"
2
+
3
+ module Pact
4
+ module Http
5
+ class AuthorizationHeaderRedactor < SimpleDelegator
6
+ def puts(*args)
7
+ __getobj__().puts(*redact_args(args))
8
+ end
9
+
10
+ def print(*args)
11
+ __getobj__().puts(*redact_args(args))
12
+ end
13
+
14
+ def <<(*args)
15
+ __getobj__().send(:<<, *redact_args(args))
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :redactions
21
+
22
+ def redact_args(args)
23
+ args.collect{ | s| redact(s) }
24
+ end
25
+
26
+ def redact(string)
27
+ return string unless string.is_a?(String)
28
+ string.gsub(/Authorization: .*\\r\\n/, "Authorization: [redacted]\\r\\n")
29
+ end
30
+ end
31
+ end
32
+ end
@@ -27,15 +27,19 @@ module Pact
27
27
  when Pact::QueryString
28
28
  from_term(term.query)
29
29
  when Pact::QueryHash
30
- from_term(term.query).map { |k, v|
31
- if v.nil?
32
- k
33
- elsif v.is_a?(Array) #For cases where there are multiple instance of the same parameter
34
- v.map { |x| "#{k}=#{escape(x)}"}.join('&')
35
- else
36
- "#{k}=#{escape(v)}"
37
- end
38
- }.join('&')
30
+ if term.original_string
31
+ term.original_string
32
+ else
33
+ from_term(term.query).map { |k, v|
34
+ if v.nil?
35
+ k
36
+ elsif v.is_a?(Array) #For cases where there are multiple instance of the same parameter
37
+ v.map { |x| "#{k}=#{escape(x)}"}.join('&')
38
+ else
39
+ "#{k}=#{escape(v)}"
40
+ end
41
+ }.join('&')
42
+ end
39
43
  when Pact::StringWithMatchingRules
40
44
  String.new(term)
41
45
  else
@@ -2,22 +2,28 @@
2
2
 
3
3
  module Pact
4
4
  module ActiveSupportSupport
5
-
6
5
  extend self
7
6
 
8
7
  def fix_all_the_things thing
9
- if thing.is_a?(Regexp)
10
- fix_regexp(thing)
11
- elsif thing.is_a?(Array)
12
- thing.each{ | it | fix_all_the_things it }
13
- elsif thing.is_a?(Hash)
14
- thing.values.each{ | it | fix_all_the_things it }
15
- elsif thing.class.name.start_with?("Pact")
16
- thing.instance_variables.collect{ | iv_name | thing.instance_variable_get(iv_name)}.each do | iv |
17
- fix_all_the_things iv
8
+ if defined?(ActiveSupport)
9
+ if thing.is_a?(Regexp)
10
+ fix_regexp(thing)
11
+ elsif thing.is_a?(Array)
12
+ thing.collect{ | it | fix_all_the_things it }
13
+ elsif thing.is_a?(Hash)
14
+ thing.each_with_object({}) { | (k, v), new_hash | new_hash[k] = fix_all_the_things(v) }
15
+ elsif thing.is_a?(Pact::Term)
16
+ # matcher Regexp is fixed in its own as_json method
17
+ thing
18
+ elsif thing.class.name.start_with?("Pact")
19
+ warn_about_regexp(thing)
20
+ thing
21
+ else
22
+ thing
18
23
  end
24
+ else
25
+ thing
19
26
  end
20
- thing
21
27
  end
22
28
 
23
29
  # ActiveSupport JSON overwrites (i.e. TRAMPLES) the json methods of the Regexp class directly
@@ -27,10 +33,7 @@ module Pact
27
33
  # original as_json to the Regexp instances in the ConsumerContract before we write them to the
28
34
  # pact file. If anyone can find a better way, please submit a pull request ASAP!
29
35
  def fix_regexp regexp
30
- def regexp.as_json options = {}
31
- {:json_class => 'Regexp', "o" => self.options, "s" => self.source }
32
- end
33
- regexp
36
+ {:json_class => 'Regexp', "o" => regexp.options, "s" => regexp.source }
34
37
  end
35
38
 
36
39
  # Having Active Support JSON loaded somehow kills the formatting of pretty_generate for objects.
@@ -49,5 +52,14 @@ module Pact
49
52
  json.gsub(/\\u([0-9A-Za-z]{4})/) {|s| [$1.to_i(16)].pack("U")}
50
53
  end
51
54
 
55
+ def warn_about_regexp(thing)
56
+ thing.instance_variables.each do | iv_name |
57
+ iv = thing.instance_variable_get(iv_name)
58
+ if iv.is_a?(Regexp)
59
+ require 'pact/configuration'
60
+ Pact.configuration.error_stream.puts("WARN: Instance variable #{iv_name} for class #{thing.class.name} is a Regexp and isn't been serialized properly. Please raise an issue at https://github.com/pact-foundation/pact-support/issues/new.")
61
+ end
62
+ end
63
+ end
52
64
  end
53
65
  end
@@ -14,7 +14,7 @@ module Pact
14
14
  @path = path
15
15
  @headers = Hash === headers ? Headers.new(headers) : headers # Could be a NullExpectation - TODO make this more elegant
16
16
  @body = body
17
- @query = is_unspecified?(query) ? query : Pact::Query.create(query)
17
+ set_query(query)
18
18
  end
19
19
 
20
20
  def to_hash
@@ -89,6 +89,18 @@ module Pact
89
89
  def display_query
90
90
  (query.nil? || query.empty?) ? '' : "?#{Pact::Reification.from_term(query)}"
91
91
  end
92
+
93
+ def set_query(query)
94
+ @query = if is_unspecified?(query)
95
+ query
96
+ else
97
+ if Pact::Query.is_a_query_object?(query)
98
+ query
99
+ else
100
+ Pact::Query.create(query)
101
+ end
102
+ end
103
+ end
92
104
  end
93
105
  end
94
106
  end
@@ -1,5 +1,5 @@
1
1
  module Pact
2
2
  module Support
3
- VERSION = "1.16.4"
3
+ VERSION = "1.16.8"
4
4
  end
5
5
  end
data/lib/pact/term.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'pact/shared/active_support_support'
2
2
  require 'json/add/regexp'
3
+ require 'pact/errors'
3
4
 
4
5
  module Pact
5
6
  class Term
@@ -25,13 +26,13 @@ module Pact
25
26
  def initialize(attributes = {})
26
27
  @generate = attributes[:generate]
27
28
  @matcher = attributes[:matcher]
28
- raise "Please specify a matcher for the Term" unless @matcher != nil
29
- raise "Please specify a value to generate for the Term" unless @generate != nil
30
- raise "Value to generate \"#{@generate}\" does not match regular expression #{@matcher.inspect}" unless @generate =~ @matcher
29
+ raise Pact::Error.new("Please specify a matcher for the Term") unless @matcher != nil
30
+ raise Pact::Error.new("Please specify a value to generate for the Term") unless @generate != nil
31
+ raise Pact::Error.new("Value to generate \"#{@generate}\" does not match regular expression #{@matcher.inspect}") unless @generate =~ @matcher
31
32
  end
32
33
 
33
34
  def to_hash
34
- { json_class: self.class.name, data: { generate: generate, matcher: fix_regexp(matcher)} }
35
+ { json_class: self.class.name, data: { generate: generate, matcher: fix_regexp(matcher) } }
35
36
  end
36
37
 
37
38
  def as_json(options = {})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact-support
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.16.4
4
+ version: 1.16.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Fraser
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2020-11-12 00:00:00.000000000 Z
15
+ date: 2021-07-27 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: randexp
@@ -48,14 +48,14 @@ dependencies:
48
48
  requirements:
49
49
  - - "~>"
50
50
  - !ruby/object:Gem::Version
51
- version: '1.1'
51
+ version: '1.9'
52
52
  type: :runtime
53
53
  prerelease: false
54
54
  version_requirements: !ruby/object:Gem::Requirement
55
55
  requirements:
56
56
  - - "~>"
57
57
  - !ruby/object:Gem::Version
58
- version: '1.1'
58
+ version: '1.9'
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: diff-lcs
61
61
  requirement: !ruby/object:Gem::Requirement
@@ -96,14 +96,14 @@ dependencies:
96
96
  requirements:
97
97
  - - "~>"
98
98
  - !ruby/object:Gem::Version
99
- version: 10.0.3
99
+ version: '13.0'
100
100
  type: :development
101
101
  prerelease: false
102
102
  version_requirements: !ruby/object:Gem::Requirement
103
103
  requirements:
104
104
  - - "~>"
105
105
  - !ruby/object:Gem::Version
106
- version: 10.0.3
106
+ version: '13.0'
107
107
  - !ruby/object:Gem::Dependency
108
108
  name: webmock
109
109
  requirement: !ruby/object:Gem::Requirement
@@ -254,6 +254,7 @@ files:
254
254
  - lib/pact/consumer_contract/string_with_matching_rules.rb
255
255
  - lib/pact/errors.rb
256
256
  - lib/pact/helpers.rb
257
+ - lib/pact/http/authorization_header_redactor.rb
257
258
  - lib/pact/logging.rb
258
259
  - lib/pact/matchers.rb
259
260
  - lib/pact/matchers/actual_type.rb
@@ -318,7 +319,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
318
319
  - !ruby/object:Gem::Version
319
320
  version: '0'
320
321
  requirements: []
321
- rubygems_version: 3.1.4
322
+ rubygems_version: 3.2.24
322
323
  signing_key:
323
324
  specification_version: 4
324
325
  summary: Shared code for Pact gems