pact-support 1.15.1 → 1.18.1
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 +137 -0
- data/README.md +1 -1
- data/lib/pact/consumer_contract/interaction_v2_parser.rb +17 -2
- data/lib/pact/consumer_contract/pact_file.rb +25 -8
- data/lib/pact/consumer_contract/query.rb +124 -0
- data/lib/pact/consumer_contract/query_hash.rb +21 -2
- data/lib/pact/http/authorization_header_redactor.rb +32 -0
- data/lib/pact/matchers/embedded_diff_formatter.rb +2 -4
- data/lib/pact/matching_rules/merge.rb +1 -1
- data/lib/pact/reification.rb +17 -11
- data/lib/pact/rspec.rb +2 -4
- data/lib/pact/shared/active_support_support.rb +27 -15
- data/lib/pact/shared/request.rb +13 -4
- data/lib/pact/support/version.rb +1 -1
- data/lib/pact/term.rb +6 -4
- data/lib/tasks/pact.rake +2 -2
- metadata +44 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b3fb2c40a2b73c204a645be5480655e98c5c41698b4958ca1acd1a98aeff1c9b
|
|
4
|
+
data.tar.gz: 2d1c53df9037d026df359c0aa818d62ba00f3e1f0def19f06b350091f54a4706
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 006d3697dafed4dca50b3c20f6cd3ade9bfc1d430b2681a489a8878cc86e274c2ede6b3976c4a8276bfcb6cd252d751d158c42ef6236273d97ab88d256aabb99
|
|
7
|
+
data.tar.gz: ac8367a3b773c10e927307324d0e5c2fc379c1e727efb2bb69288c0ea0d6548555201bbc6168b52b0dfd55534fa2ba2a25eabeb842c8cadbff3f7a4be5d08f35
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,140 @@
|
|
|
1
|
+
<a name="v1.18.1"></a>
|
|
2
|
+
### v1.18.1 (2022-08-17)
|
|
3
|
+
|
|
4
|
+
#### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* use send to invoke remove_method when removing as_json from Regexp ([cb29cdd](/../../commit/cb29cdd))
|
|
7
|
+
|
|
8
|
+
<a name="v1.18.0"></a>
|
|
9
|
+
### v1.18.0 (2022-03-28)
|
|
10
|
+
|
|
11
|
+
#### Features
|
|
12
|
+
|
|
13
|
+
* replace term-ansicolor with rainbow ([e8b6ada](/../../commit/e8b6ada))
|
|
14
|
+
|
|
15
|
+
#### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* Fixup ruby warnings (#96) ([cee7113](/../../commit/cee7113))
|
|
18
|
+
|
|
19
|
+
<a name="v1.17.0"></a>
|
|
20
|
+
### v1.17.0 (2021-10-01)
|
|
21
|
+
|
|
22
|
+
#### Features
|
|
23
|
+
|
|
24
|
+
* allow SSL verification to be disabled by setting environment variable PACT_DISABLE_SSL_VERIFICATION=true ([dd39c04](/../../commit/dd39c04))
|
|
25
|
+
|
|
26
|
+
<a name="v1.16.10"></a>
|
|
27
|
+
### v1.16.10 (2021-10-01)
|
|
28
|
+
|
|
29
|
+
#### Bug Fixes
|
|
30
|
+
|
|
31
|
+
* change expgen to a runtime dependency ([da81634](/../../commit/da81634))
|
|
32
|
+
|
|
33
|
+
<a name="v1.16.9"></a>
|
|
34
|
+
### v1.16.9 (2021-09-30)
|
|
35
|
+
|
|
36
|
+
#### Bug Fixes
|
|
37
|
+
|
|
38
|
+
* remove randexp dependency (#91) ([794fd4e](/../../commit/794fd4e))
|
|
39
|
+
|
|
40
|
+
<a name="v1.16.8"></a>
|
|
41
|
+
### v1.16.8 (2021-07-27)
|
|
42
|
+
|
|
43
|
+
#### Bug Fixes
|
|
44
|
+
|
|
45
|
+
* log HTTP request for pacts retrieved by URL when requested with verbose=true ([3288b81](/../../commit/3288b81))
|
|
46
|
+
|
|
47
|
+
<a name="v1.16.7"></a>
|
|
48
|
+
### v1.16.7 (2021-01-28)
|
|
49
|
+
|
|
50
|
+
#### Bug Fixes
|
|
51
|
+
|
|
52
|
+
* dynamically parse actual query to match expected format ([a86a3e3](/../../commit/a86a3e3))
|
|
53
|
+
|
|
54
|
+
<a name="v1.16.6"></a>
|
|
55
|
+
### v1.16.6 (2021-01-28)
|
|
56
|
+
|
|
57
|
+
#### Bug Fixes
|
|
58
|
+
|
|
59
|
+
* raise Pact::Error not RuntimeError when invalid constructor arguments are supplied to a Pact::Term ([d9fb8ea](/../../commit/d9fb8ea))
|
|
60
|
+
* update active support support for Ruby 3.0 ([6c30d42](/../../commit/6c30d42))
|
|
61
|
+
|
|
62
|
+
<a name="v1.16.5"></a>
|
|
63
|
+
### v1.16.5 (2020-11-25)
|
|
64
|
+
|
|
65
|
+
#### Bug Fixes
|
|
66
|
+
|
|
67
|
+
* 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))
|
|
68
|
+
|
|
69
|
+
<a name="v1.16.4"></a>
|
|
70
|
+
### v1.16.4 (2020-11-13)
|
|
71
|
+
|
|
72
|
+
#### Bug Fixes
|
|
73
|
+
|
|
74
|
+
* ensure expected and actual query strings are parsed consistently ([4e9ca9c](/../../commit/4e9ca9c))
|
|
75
|
+
|
|
76
|
+
<a name="v1.16.3"></a>
|
|
77
|
+
### v1.16.3 (2020-11-10)
|
|
78
|
+
|
|
79
|
+
#### Bug Fixes
|
|
80
|
+
|
|
81
|
+
* add missing params_hash_has_key ([700efa7](/../../commit/700efa7))
|
|
82
|
+
|
|
83
|
+
<a name="v1.16.2"></a>
|
|
84
|
+
### v1.16.2 (2020-11-07)
|
|
85
|
+
|
|
86
|
+
#### Bug Fixes
|
|
87
|
+
|
|
88
|
+
* removed undefined depth from query ([53a373d](/../../commit/53a373d))
|
|
89
|
+
|
|
90
|
+
<a name="v1.16.1"></a>
|
|
91
|
+
### v1.16.1 (2020-11-06)
|
|
92
|
+
|
|
93
|
+
#### Bug Fixes
|
|
94
|
+
|
|
95
|
+
* add missing params_hash_type? from Rack ([3195b0a](/../../commit/3195b0a))
|
|
96
|
+
|
|
97
|
+
<a name="v1.16.0"></a>
|
|
98
|
+
### v1.16.0 (2020-11-04)
|
|
99
|
+
|
|
100
|
+
#### Features
|
|
101
|
+
|
|
102
|
+
* remove runtime dependency on rspec ([aca30e2](/../../commit/aca30e2))
|
|
103
|
+
|
|
104
|
+
<a name="v1.15.5"></a>
|
|
105
|
+
### v1.15.5 (2020-11-04)
|
|
106
|
+
|
|
107
|
+
#### Bug Fixes
|
|
108
|
+
|
|
109
|
+
* add missing outputs to release workflow ([d565d0f](/../../commit/d565d0f))
|
|
110
|
+
* try different output syntax ([b11e8fb](/../../commit/b11e8fb))
|
|
111
|
+
|
|
112
|
+
<a name="v1.15.4"></a>
|
|
113
|
+
### v1.15.4 (2020-11-04)
|
|
114
|
+
|
|
115
|
+
#### Bug Fixes
|
|
116
|
+
|
|
117
|
+
* update release gem action version ([9dead58](/../../commit/9dead58))
|
|
118
|
+
|
|
119
|
+
<a name="v1.15.3"></a>
|
|
120
|
+
### v1.15.3 (2020-11-04)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
#### Bug Fixes
|
|
124
|
+
|
|
125
|
+
* release workflow ([4bdf8d8](/../../commit/4bdf8d8))
|
|
126
|
+
* not actually a fix, just triggering new release ([74038a5](/../../commit/74038a5))
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
<a name="v1.15.2"></a>
|
|
130
|
+
### v1.15.2 (2020-11-04)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
#### Bug Fixes
|
|
134
|
+
|
|
135
|
+
* parse query string to hash for v2 interactions ([faff17c](/../../commit/faff17c))
|
|
136
|
+
|
|
137
|
+
|
|
1
138
|
<a name="v1.15.0"></a>
|
|
2
139
|
### v1.15.0 (2020-04-30)
|
|
3
140
|
|
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
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'pact/consumer_contract/request'
|
|
2
2
|
require 'pact/consumer_contract/response'
|
|
3
3
|
require 'pact/consumer_contract/provider_state'
|
|
4
|
+
require 'pact/consumer_contract/query'
|
|
4
5
|
require 'pact/symbolize_keys'
|
|
5
6
|
require 'pact/matching_rules'
|
|
6
7
|
require 'pact/errors'
|
|
@@ -15,14 +16,28 @@ module Pact
|
|
|
15
16
|
response = parse_response(hash['response'], options)
|
|
16
17
|
provider_states = parse_provider_states(hash['providerState'] || hash['provider_state'])
|
|
17
18
|
metadata = parse_metadata(hash['metadata'])
|
|
18
|
-
Interaction.new(symbolize_keys(hash).merge(request: request,
|
|
19
|
-
response: response,
|
|
19
|
+
Interaction.new(symbolize_keys(hash).merge(request: request,
|
|
20
|
+
response: response,
|
|
20
21
|
provider_states: provider_states,
|
|
21
22
|
metadata: metadata))
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
def self.parse_request request_hash, options
|
|
26
|
+
original_query_string = request_hash['query']
|
|
27
|
+
query_is_string = original_query_string.is_a?(String)
|
|
28
|
+
if query_is_string
|
|
29
|
+
request_hash = request_hash.dup
|
|
30
|
+
request_hash['query'] = Pact::Query.parse_string(request_hash['query'])
|
|
31
|
+
end
|
|
32
|
+
# The query has to be a hash at this stage for the matching rules to be applied
|
|
25
33
|
request_hash = Pact::MatchingRules.merge(request_hash, request_hash['matchingRules'], options)
|
|
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
|
|
26
41
|
Pact::Request::Expected.from_hash(request_hash)
|
|
27
42
|
end
|
|
28
43
|
|
|
@@ -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
|
|
@@ -33,7 +35,7 @@ module Pact
|
|
|
33
35
|
def save_pactfile_to_tmp pact, name
|
|
34
36
|
::FileUtils.mkdir_p Pact.configuration.tmp_dir
|
|
35
37
|
::File.open(Pact.configuration.tmp_dir + "/#{name}", "w") { |file| file << pact}
|
|
36
|
-
rescue Errno::EROFS
|
|
38
|
+
rescue Errno::EROFS
|
|
37
39
|
# do nothing, probably on RunKit
|
|
38
40
|
end
|
|
39
41
|
|
|
@@ -54,9 +56,9 @@ module Pact
|
|
|
54
56
|
def get_remote_with_retry(uri_string, options)
|
|
55
57
|
uri = URI(uri_string)
|
|
56
58
|
if uri.userinfo
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
options[:username] = uri.user unless options[:username]
|
|
60
|
+
options[:password] = uri.password unless options[:password]
|
|
61
|
+
end
|
|
60
62
|
((options[:retry_limit] || RETRY_LIMIT) + 1).times do |i|
|
|
61
63
|
begin
|
|
62
64
|
response = get_remote(uri, options)
|
|
@@ -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,18 @@ 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 verbose?(options)
|
|
112
|
+
if disable_ssl_verification?
|
|
113
|
+
if verbose?(options)
|
|
114
|
+
Pact.configuration.output_stream.puts("SSL verification is disabled")
|
|
115
|
+
end
|
|
116
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
117
|
+
end
|
|
109
118
|
http
|
|
110
119
|
end
|
|
111
120
|
|
|
@@ -136,5 +145,13 @@ module Pact
|
|
|
136
145
|
def windows_safe(uri)
|
|
137
146
|
uri.start_with?("http") ? uri : uri.gsub("\\", File::SEPARATOR)
|
|
138
147
|
end
|
|
148
|
+
|
|
149
|
+
def verbose?(options)
|
|
150
|
+
options[:verbose] || ENV['VERBOSE'] == 'true'
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def disable_ssl_verification?
|
|
154
|
+
ENV['PACT_DISABLE_SSL_VERIFICATION'] == 'true' || ENV['PACT_BROKER_DISABLE_SSL_VERIFICATION'] == 'true'
|
|
155
|
+
end
|
|
139
156
|
end
|
|
140
157
|
end
|
|
@@ -3,6 +3,11 @@ require 'pact/consumer_contract/query_string'
|
|
|
3
3
|
|
|
4
4
|
module Pact
|
|
5
5
|
class Query
|
|
6
|
+
DEFAULT_SEP = /[&;] */n
|
|
7
|
+
COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n }
|
|
8
|
+
|
|
9
|
+
class NestedQuery < Hash; end
|
|
10
|
+
|
|
6
11
|
def self.create query
|
|
7
12
|
if query.is_a? Hash
|
|
8
13
|
Pact::QueryHash.new(query)
|
|
@@ -10,5 +15,124 @@ module Pact
|
|
|
10
15
|
Pact::QueryString.new(query)
|
|
11
16
|
end
|
|
12
17
|
end
|
|
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
|
+
|
|
27
|
+
def self.parse_string query_string
|
|
28
|
+
parsed_query = parse_string_as_non_nested_query(query_string)
|
|
29
|
+
|
|
30
|
+
# If Rails nested params...
|
|
31
|
+
if parsed_query.keys.any?{ | key| key =~ /\[.*\]/ }
|
|
32
|
+
parse_string_as_nested_query(query_string)
|
|
33
|
+
else
|
|
34
|
+
parsed_query.each_with_object({}) do | (key, value), new_hash |
|
|
35
|
+
new_hash[key] = [*value]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Ripped from Rack to avoid adding an unnecessary dependency, thank you Rack
|
|
41
|
+
# https://github.com/rack/rack/blob/649c72bab9e7b50d657b5b432d0c205c95c2be07/lib/rack/utils.rb
|
|
42
|
+
def self.parse_string_as_non_nested_query(qs, d = nil, &unescaper)
|
|
43
|
+
unescaper ||= method(:unescape)
|
|
44
|
+
|
|
45
|
+
params = {}
|
|
46
|
+
|
|
47
|
+
(qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
|
|
48
|
+
next if p.empty?
|
|
49
|
+
k, v = p.split('=', 2).map!(&unescaper)
|
|
50
|
+
|
|
51
|
+
if cur = params[k]
|
|
52
|
+
if cur.class == Array
|
|
53
|
+
params[k] << v
|
|
54
|
+
else
|
|
55
|
+
params[k] = [cur, v]
|
|
56
|
+
end
|
|
57
|
+
else
|
|
58
|
+
params[k] = v
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
return params.to_h
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.parse_string_as_nested_query(qs, d = nil)
|
|
66
|
+
params = {}
|
|
67
|
+
|
|
68
|
+
unless qs.nil? || qs.empty?
|
|
69
|
+
(qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
|
|
70
|
+
k, v = p.split('=', 2).map! { |s| unescape(s) }
|
|
71
|
+
|
|
72
|
+
normalize_params(params, k, v)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
return NestedQuery[params.to_h]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.normalize_params(params, name, v)
|
|
80
|
+
name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
|
|
81
|
+
k = $1 || ''
|
|
82
|
+
after = $' || ''
|
|
83
|
+
|
|
84
|
+
if k.empty?
|
|
85
|
+
if !v.nil? && name == "[]"
|
|
86
|
+
return Array(v)
|
|
87
|
+
else
|
|
88
|
+
return
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if after == ''
|
|
93
|
+
params[k] = v
|
|
94
|
+
elsif after == "["
|
|
95
|
+
params[name] = v
|
|
96
|
+
elsif after == "[]"
|
|
97
|
+
params[k] ||= []
|
|
98
|
+
raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
|
|
99
|
+
params[k] << v
|
|
100
|
+
elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
|
|
101
|
+
child_key = $1
|
|
102
|
+
params[k] ||= []
|
|
103
|
+
raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
|
|
104
|
+
if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key)
|
|
105
|
+
normalize_params(params[k].last, child_key, v)
|
|
106
|
+
else
|
|
107
|
+
params[k] << normalize_params({}, child_key, v)
|
|
108
|
+
end
|
|
109
|
+
else
|
|
110
|
+
params[k] ||= {}
|
|
111
|
+
raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
|
|
112
|
+
params[k] = normalize_params(params[k], after, v)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
params
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self.params_hash_type?(obj)
|
|
119
|
+
obj.is_a?(Hash)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def self.params_hash_has_key?(hash, key)
|
|
123
|
+
return false if key =~ /\[\]/
|
|
124
|
+
|
|
125
|
+
key.split(/[\[\]]+/).inject(hash) do |h, part|
|
|
126
|
+
next h if part == ''
|
|
127
|
+
return false unless params_hash_type?(h) && h.key?(part)
|
|
128
|
+
h[part]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
true
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def self.unescape(s, encoding = Encoding::UTF_8)
|
|
135
|
+
URI.decode_www_form_component(s, encoding)
|
|
136
|
+
end
|
|
13
137
|
end
|
|
14
138
|
end
|
|
@@ -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
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
require 'pact/shared/active_support_support'
|
|
2
|
-
require '
|
|
2
|
+
require 'rainbow'
|
|
3
3
|
|
|
4
4
|
module Pact
|
|
5
5
|
module Matchers
|
|
6
6
|
class EmbeddedDiffFormatter
|
|
7
7
|
|
|
8
8
|
include Pact::ActiveSupportSupport
|
|
9
|
-
C = ::Term::ANSIColor
|
|
10
|
-
|
|
11
9
|
|
|
12
10
|
EXPECTED = /"EXPECTED([A-Z_]*)":/
|
|
13
11
|
|
|
@@ -53,7 +51,7 @@ module Pact
|
|
|
53
51
|
end
|
|
54
52
|
|
|
55
53
|
def coloured_key match, colour
|
|
56
|
-
'"' +
|
|
54
|
+
'"' + Rainbow(match.downcase.gsub(/^"|":$/,'')).send(colour) + '":'
|
|
57
55
|
end
|
|
58
56
|
|
|
59
57
|
end
|
data/lib/pact/reification.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'expgen'
|
|
2
2
|
require 'pact/term'
|
|
3
3
|
require 'pact/something_like'
|
|
4
4
|
require 'pact/array_like'
|
|
@@ -13,8 +13,10 @@ module Pact
|
|
|
13
13
|
|
|
14
14
|
def self.from_term(term)
|
|
15
15
|
case term
|
|
16
|
-
when Pact::Term,
|
|
16
|
+
when Pact::Term, Pact::SomethingLike, Pact::ArrayLike
|
|
17
17
|
from_term(term.generate)
|
|
18
|
+
when Regexp
|
|
19
|
+
from_term(Expgen.gen(term))
|
|
18
20
|
when Hash
|
|
19
21
|
term.inject({}) do |mem, (key,t)|
|
|
20
22
|
mem[key] = from_term(t)
|
|
@@ -27,15 +29,19 @@ module Pact
|
|
|
27
29
|
when Pact::QueryString
|
|
28
30
|
from_term(term.query)
|
|
29
31
|
when Pact::QueryHash
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
v.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
if term.original_string
|
|
33
|
+
term.original_string
|
|
34
|
+
else
|
|
35
|
+
from_term(term.query).map { |k, v|
|
|
36
|
+
if v.nil?
|
|
37
|
+
k
|
|
38
|
+
elsif v.is_a?(Array) #For cases where there are multiple instance of the same parameter
|
|
39
|
+
v.map { |x| "#{k}=#{escape(x)}"}.join('&')
|
|
40
|
+
else
|
|
41
|
+
"#{k}=#{escape(v)}"
|
|
42
|
+
end
|
|
43
|
+
}.join('&')
|
|
44
|
+
end
|
|
39
45
|
when Pact::StringWithMatchingRules
|
|
40
46
|
String.new(term)
|
|
41
47
|
else
|
data/lib/pact/rspec.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require 'rspec'
|
|
2
1
|
# This is horrible, must work out a better way of doing this
|
|
3
2
|
module Pact
|
|
4
3
|
module RSpec
|
|
@@ -19,7 +18,6 @@ module Pact
|
|
|
19
18
|
require 'pact/provider/rspec/formatter_rspec_2'
|
|
20
19
|
Pact::Provider::RSpec::Formatter2
|
|
21
20
|
end
|
|
22
|
-
|
|
23
21
|
end
|
|
24
22
|
|
|
25
23
|
def self.full_description example
|
|
@@ -31,11 +29,11 @@ module Pact
|
|
|
31
29
|
end
|
|
32
30
|
|
|
33
31
|
def self.is_rspec_3
|
|
34
|
-
::RSpec::Core::Formatters.respond_to?(:register)
|
|
32
|
+
defined?(::RSpec) && ::RSpec::Core::Formatters.respond_to?(:register)
|
|
35
33
|
end
|
|
36
34
|
|
|
37
35
|
def self.is_rspec_2
|
|
38
|
-
!is_rspec_3
|
|
36
|
+
defined?(::RSpec) && !is_rspec_3
|
|
39
37
|
end
|
|
40
38
|
|
|
41
39
|
def self.with_rspec_3
|
|
@@ -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
|
@@ -3,9 +3,7 @@ require 'pact/consumer_contract/headers'
|
|
|
3
3
|
require 'pact/consumer_contract/query'
|
|
4
4
|
|
|
5
5
|
module Pact
|
|
6
|
-
|
|
7
6
|
module Request
|
|
8
|
-
|
|
9
7
|
class Base
|
|
10
8
|
include Pact::SymbolizeKeys
|
|
11
9
|
|
|
@@ -16,7 +14,7 @@ module Pact
|
|
|
16
14
|
@path = path
|
|
17
15
|
@headers = Hash === headers ? Headers.new(headers) : headers # Could be a NullExpectation - TODO make this more elegant
|
|
18
16
|
@body = body
|
|
19
|
-
|
|
17
|
+
set_query(query)
|
|
20
18
|
end
|
|
21
19
|
|
|
22
20
|
def to_hash
|
|
@@ -92,6 +90,17 @@ module Pact
|
|
|
92
90
|
(query.nil? || query.empty?) ? '' : "?#{Pact::Reification.from_term(query)}"
|
|
93
91
|
end
|
|
94
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
|
|
95
104
|
end
|
|
96
105
|
end
|
|
97
|
-
end
|
|
106
|
+
end
|
data/lib/pact/support/version.rb
CHANGED
data/lib/pact/term.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
require 'pact/shared/active_support_support'
|
|
2
|
+
Regexp.send(:remove_method, :as_json) if Regexp.method_defined?(:as_json)
|
|
2
3
|
require 'json/add/regexp'
|
|
4
|
+
require 'pact/errors'
|
|
3
5
|
|
|
4
6
|
module Pact
|
|
5
7
|
class Term
|
|
@@ -25,13 +27,13 @@ module Pact
|
|
|
25
27
|
def initialize(attributes = {})
|
|
26
28
|
@generate = attributes[:generate]
|
|
27
29
|
@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
|
|
30
|
+
raise Pact::Error.new("Please specify a matcher for the Term") unless @matcher != nil
|
|
31
|
+
raise Pact::Error.new("Please specify a value to generate for the Term") unless @generate != nil
|
|
32
|
+
raise Pact::Error.new("Value to generate \"#{@generate}\" does not match regular expression #{@matcher.inspect}") unless @generate =~ @matcher
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
def to_hash
|
|
34
|
-
{ json_class: self.class.name, data: { generate: generate, matcher: fix_regexp(matcher)} }
|
|
36
|
+
{ json_class: self.class.name, data: { generate: generate, matcher: fix_regexp(matcher) } }
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
def as_json(options = {})
|
data/lib/tasks/pact.rake
CHANGED
|
@@ -15,12 +15,12 @@ namespace :pact do
|
|
|
15
15
|
|
|
16
16
|
desc "Verifies the pact at the given URI against this service provider."
|
|
17
17
|
task 'verify:at', :pact_uri do | t, args |
|
|
18
|
-
require '
|
|
18
|
+
require 'rainbow'
|
|
19
19
|
require 'pact/tasks/task_helper'
|
|
20
20
|
|
|
21
21
|
include Pact::TaskHelper
|
|
22
22
|
|
|
23
|
-
abort(
|
|
23
|
+
abort(Rainbow("Please provide a pact URI. eg. rake pact:verify:at[../my-consumer/spec/pacts/my_consumer-my_provider.json]").red) unless args[:pact_uri]
|
|
24
24
|
handle_verification_failure do
|
|
25
25
|
execute_pact_verify args[:pact_uri]
|
|
26
26
|
end
|
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.
|
|
4
|
+
version: 1.18.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- James Fraser
|
|
@@ -9,81 +9,101 @@ authors:
|
|
|
9
9
|
- Brent Snook
|
|
10
10
|
- Ronald Holshausen
|
|
11
11
|
- Beth Skurrie
|
|
12
|
-
autorequire:
|
|
12
|
+
autorequire:
|
|
13
13
|
bindir: bin
|
|
14
14
|
cert_chain: []
|
|
15
|
-
date:
|
|
15
|
+
date: 2022-08-16 00:00:00.000000000 Z
|
|
16
16
|
dependencies:
|
|
17
17
|
- !ruby/object:Gem::Dependency
|
|
18
|
-
name:
|
|
18
|
+
name: rainbow
|
|
19
19
|
requirement: !ruby/object:Gem::Requirement
|
|
20
20
|
requirements:
|
|
21
21
|
- - "~>"
|
|
22
22
|
- !ruby/object:Gem::Version
|
|
23
|
-
version:
|
|
23
|
+
version: 3.1.1
|
|
24
24
|
type: :runtime
|
|
25
25
|
prerelease: false
|
|
26
26
|
version_requirements: !ruby/object:Gem::Requirement
|
|
27
27
|
requirements:
|
|
28
28
|
- - "~>"
|
|
29
29
|
- !ruby/object:Gem::Version
|
|
30
|
-
version:
|
|
30
|
+
version: 3.1.1
|
|
31
31
|
- !ruby/object:Gem::Dependency
|
|
32
|
-
name:
|
|
32
|
+
name: awesome_print
|
|
33
33
|
requirement: !ruby/object:Gem::Requirement
|
|
34
34
|
requirements:
|
|
35
|
-
- - "
|
|
35
|
+
- - "~>"
|
|
36
36
|
- !ruby/object:Gem::Version
|
|
37
|
-
version: '
|
|
37
|
+
version: '1.9'
|
|
38
38
|
type: :runtime
|
|
39
39
|
prerelease: false
|
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
|
41
41
|
requirements:
|
|
42
|
-
- - "
|
|
42
|
+
- - "~>"
|
|
43
43
|
- !ruby/object:Gem::Version
|
|
44
|
-
version: '
|
|
44
|
+
version: '1.9'
|
|
45
45
|
- !ruby/object:Gem::Dependency
|
|
46
|
-
name:
|
|
46
|
+
name: diff-lcs
|
|
47
47
|
requirement: !ruby/object:Gem::Requirement
|
|
48
48
|
requirements:
|
|
49
49
|
- - "~>"
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
|
-
version: '1.
|
|
51
|
+
version: '1.4'
|
|
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.4'
|
|
59
59
|
- !ruby/object:Gem::Dependency
|
|
60
|
-
name:
|
|
60
|
+
name: expgen
|
|
61
61
|
requirement: !ruby/object:Gem::Requirement
|
|
62
62
|
requirements:
|
|
63
63
|
- - "~>"
|
|
64
64
|
- !ruby/object:Gem::Version
|
|
65
|
-
version: '
|
|
65
|
+
version: '0.1'
|
|
66
66
|
type: :runtime
|
|
67
67
|
prerelease: false
|
|
68
68
|
version_requirements: !ruby/object:Gem::Requirement
|
|
69
69
|
requirements:
|
|
70
70
|
- - "~>"
|
|
71
71
|
- !ruby/object:Gem::Version
|
|
72
|
-
version: '
|
|
72
|
+
version: '0.1'
|
|
73
|
+
- !ruby/object:Gem::Dependency
|
|
74
|
+
name: rspec
|
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
|
76
|
+
requirements:
|
|
77
|
+
- - ">="
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
version: '2.14'
|
|
80
|
+
- - "<"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '4.0'
|
|
83
|
+
type: :development
|
|
84
|
+
prerelease: false
|
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '2.14'
|
|
90
|
+
- - "<"
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '4.0'
|
|
73
93
|
- !ruby/object:Gem::Dependency
|
|
74
94
|
name: rake
|
|
75
95
|
requirement: !ruby/object:Gem::Requirement
|
|
76
96
|
requirements:
|
|
77
97
|
- - "~>"
|
|
78
98
|
- !ruby/object:Gem::Version
|
|
79
|
-
version:
|
|
99
|
+
version: '13.0'
|
|
80
100
|
type: :development
|
|
81
101
|
prerelease: false
|
|
82
102
|
version_requirements: !ruby/object:Gem::Requirement
|
|
83
103
|
requirements:
|
|
84
104
|
- - "~>"
|
|
85
105
|
- !ruby/object:Gem::Version
|
|
86
|
-
version:
|
|
106
|
+
version: '13.0'
|
|
87
107
|
- !ruby/object:Gem::Dependency
|
|
88
108
|
name: webmock
|
|
89
109
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -196,7 +216,7 @@ dependencies:
|
|
|
196
216
|
- - "~>"
|
|
197
217
|
- !ruby/object:Gem::Version
|
|
198
218
|
version: '0.5'
|
|
199
|
-
description:
|
|
219
|
+
description:
|
|
200
220
|
email:
|
|
201
221
|
- james.fraser@alumni.swinburne.edu
|
|
202
222
|
- sergei.matheson@gmail.com
|
|
@@ -234,6 +254,7 @@ files:
|
|
|
234
254
|
- lib/pact/consumer_contract/string_with_matching_rules.rb
|
|
235
255
|
- lib/pact/errors.rb
|
|
236
256
|
- lib/pact/helpers.rb
|
|
257
|
+
- lib/pact/http/authorization_header_redactor.rb
|
|
237
258
|
- lib/pact/logging.rb
|
|
238
259
|
- lib/pact/matchers.rb
|
|
239
260
|
- lib/pact/matchers/actual_type.rb
|
|
@@ -283,7 +304,7 @@ homepage: https://github.com/pact-foundation/pact-support
|
|
|
283
304
|
licenses:
|
|
284
305
|
- MIT
|
|
285
306
|
metadata: {}
|
|
286
|
-
post_install_message:
|
|
307
|
+
post_install_message:
|
|
287
308
|
rdoc_options: []
|
|
288
309
|
require_paths:
|
|
289
310
|
- lib
|
|
@@ -298,8 +319,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
298
319
|
- !ruby/object:Gem::Version
|
|
299
320
|
version: '0'
|
|
300
321
|
requirements: []
|
|
301
|
-
rubygems_version: 3.
|
|
302
|
-
signing_key:
|
|
322
|
+
rubygems_version: 3.3.20
|
|
323
|
+
signing_key:
|
|
303
324
|
specification_version: 4
|
|
304
325
|
summary: Shared code for Pact gems
|
|
305
326
|
test_files: []
|