pact-support 1.16.4 → 1.16.8

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 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