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 +4 -4
- data/CHANGELOG.md +29 -0
- data/README.md +1 -1
- data/lib/pact/consumer_contract/interaction_v2_parser.rb +12 -2
- data/lib/pact/consumer_contract/pact_file.rb +7 -4
- data/lib/pact/consumer_contract/query.rb +15 -5
- data/lib/pact/consumer_contract/query_hash.rb +21 -2
- data/lib/pact/http/authorization_header_redactor.rb +32 -0
- data/lib/pact/reification.rb +13 -9
- data/lib/pact/shared/active_support_support.rb +27 -15
- data/lib/pact/shared/request.rb +13 -1
- data/lib/pact/support/version.rb +1 -1
- data/lib/pact/term.rb +5 -4
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03a46a4e6bb3335f9acc353c80f485bd22d92e6b137e85fd25559a141eb282da
|
4
|
+
data.tar.gz: 967af721b125b04d725e5743a6759c6215b3b2af5e99526b9bbcfdf019ae0f05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
3
|
+

|
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
|
-
|
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
|
-
|
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
|
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 =
|
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
|
-
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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
|
data/lib/pact/reification.rb
CHANGED
@@ -27,15 +27,19 @@ module Pact
|
|
27
27
|
when Pact::QueryString
|
28
28
|
from_term(term.query)
|
29
29
|
when Pact::QueryHash
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
v.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
10
|
-
|
11
|
-
|
12
|
-
thing.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
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
|
data/lib/pact/shared/request.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/pact/support/version.rb
CHANGED
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
|
+
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:
|
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.
|
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.
|
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:
|
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:
|
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.
|
322
|
+
rubygems_version: 3.2.24
|
322
323
|
signing_key:
|
323
324
|
specification_version: 4
|
324
325
|
summary: Shared code for Pact gems
|