pact-support 1.4.0 → 1.8.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +143 -0
  3. data/lib/pact/configuration.rb +4 -0
  4. data/lib/pact/consumer_contract/consumer_contract.rb +19 -8
  5. data/lib/pact/consumer_contract/http_consumer_contract_parser.rb +37 -0
  6. data/lib/pact/consumer_contract/interaction.rb +57 -56
  7. data/lib/pact/consumer_contract/interaction_parser.rb +23 -0
  8. data/lib/pact/consumer_contract/interaction_v2_parser.rb +34 -0
  9. data/lib/pact/consumer_contract/interaction_v3_parser.rb +73 -0
  10. data/lib/pact/consumer_contract/pact_file.rb +24 -24
  11. data/lib/pact/consumer_contract/provider_state.rb +34 -0
  12. data/lib/pact/consumer_contract/query.rb +0 -2
  13. data/lib/pact/consumer_contract/query_hash.rb +6 -0
  14. data/lib/pact/consumer_contract/query_string.rb +2 -2
  15. data/lib/pact/consumer_contract/request.rb +1 -5
  16. data/lib/pact/consumer_contract/string_with_matching_rules.rb +17 -0
  17. data/lib/pact/matchers/multipart_form_diff_formatter.rb +41 -0
  18. data/lib/pact/matching_rules/merge.rb +43 -28
  19. data/lib/pact/matching_rules/v3/extract.rb +94 -0
  20. data/lib/pact/matching_rules/v3/merge.rb +135 -0
  21. data/lib/pact/matching_rules.rb +19 -6
  22. data/lib/pact/reification.rb +6 -3
  23. data/lib/pact/shared/multipart_form_differ.rb +14 -0
  24. data/lib/pact/specification_version.rb +18 -0
  25. data/lib/pact/support/version.rb +1 -1
  26. data/script/release.sh +1 -1
  27. data/spec/fixtures/multipart-form-diff.txt +9 -0
  28. data/spec/fixtures/not-a-pact.json +3 -0
  29. data/spec/fixtures/pact-http-v2.json +36 -0
  30. data/spec/fixtures/pact-http-v3.json +36 -0
  31. data/spec/integration/matching_rules_extract_and_merge_spec.rb +41 -4
  32. data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +54 -31
  33. data/spec/lib/pact/consumer_contract/http_consumer_contract_parser_spec.rb +25 -0
  34. data/spec/lib/pact/consumer_contract/interaction_parser_spec.rb +62 -0
  35. data/spec/lib/pact/consumer_contract/interaction_spec.rb +2 -26
  36. data/spec/lib/pact/consumer_contract/interaction_v2_parser_spec.rb +54 -0
  37. data/spec/lib/pact/consumer_contract/interaction_v3_parser_spec.rb +48 -0
  38. data/spec/lib/pact/consumer_contract/pact_file_spec.rb +9 -0
  39. data/spec/lib/pact/consumer_contract/query_hash_spec.rb +23 -0
  40. data/spec/lib/pact/matchers/multipart_form_diff_formatter_spec.rb +36 -0
  41. data/spec/lib/pact/matching_rules/merge_spec.rb +198 -110
  42. data/spec/lib/pact/matching_rules/v3/extract_spec.rb +238 -0
  43. data/spec/lib/pact/matching_rules/v3/merge_spec.rb +462 -0
  44. data/spec/lib/pact/matching_rules_spec.rb +82 -0
  45. data/spec/lib/pact/reification_spec.rb +18 -5
  46. data/spec/lib/pact/shared/multipart_form_differ_spec.rb +39 -0
  47. data/spec/support/factories.rb +5 -0
  48. data/tasks/spec.rake +0 -1
  49. metadata +40 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d63ce6f1b637b9ec8c1aa7c097631c13134c8085
4
- data.tar.gz: e7f099a1364dd8e6ea4da06c5e6c15e6d1b83b38
3
+ metadata.gz: 2e798766a40ccdcb43c8aed0bfbb4ee222c266db
4
+ data.tar.gz: fb9ab7ab4bac90b552b8c993ff582f035b5a9e00
5
5
  SHA512:
6
- metadata.gz: 6fab573b4105cb73ab146e406cfddbb56508160324e639b35a287f823a1b8c1570347768ef0198dbcf7454ea9dbfef7f0a53f9e3b48c9e22f430c5cd4d45548e
7
- data.tar.gz: 424fdc09077746fda17301499934ef326c6f1af664baac0cc08e5f3d3c318d1047a3a7a95db7b90cf82d6139da774cb579fedb0a56929aba6fdc66dbaf15ca0d
6
+ metadata.gz: 3d0363e0c4f19d960c4301cb96918d0eed195bd149eef1f4ce0ea4707c7629abf24a7c496e1918fb73f7b806bfea730e5a28397b972ea69a947e332bd2cd7cff
7
+ data.tar.gz: 0ec07b703a4abe989d0507d2f91f0aa96a76b16142e2115abca1ca355d1b0e4333e733c9d0f9142c33674116995a907ca58781d0b07ba970625253a4eebe1df6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,146 @@
1
+ <a name="v1.8.0"></a>
2
+ ### v1.8.0 (2018-10-01)
3
+
4
+
5
+ #### Features
6
+
7
+ * **v3**
8
+ * parse array of provider states with params ([4471df3](/../../commit/4471df3))
9
+
10
+
11
+ <a name="v1.7.2"></a>
12
+ ### v1.7.2 (2018-08-09)
13
+
14
+
15
+ #### Bug Fixes
16
+
17
+ * correctly handle Pact.like and Pact.each_like at top level of body ([f37c283](/../../commit/f37c283))
18
+
19
+
20
+ <a name="v1.7.1"></a>
21
+ ### v1.7.1 (2018-08-09)
22
+
23
+
24
+ #### Bug Fixes
25
+
26
+ * remove incorrect warning messages about matching rules being ignored ([30328e0](/../../commit/30328e0))
27
+
28
+
29
+ <a name="v1.7.0"></a>
30
+ ### v1.7.0 (2018-08-07)
31
+
32
+
33
+ #### Features
34
+
35
+ * add support for multipart/form ([8ed4332](/../../commit/8ed4332))
36
+
37
+
38
+ <a name="v1.6.6"></a>
39
+ ### v1.6.6 (2018-07-25)
40
+
41
+
42
+ #### Bug Fixes
43
+
44
+ * correctly handle an 'each like' inside a 'like' ([7dc76dc](/../../commit/7dc76dc))
45
+
46
+
47
+ <a name="v1.6.5"></a>
48
+ ### v1.6.5 (2018-07-23)
49
+
50
+
51
+ #### Features
52
+
53
+ * use 0 as the nil pact specification version ([88e4750](/../../commit/88e4750))
54
+ * reify StringWithMatchingRules to a String ([a025dd3](/../../commit/a025dd3))
55
+ * parse String response and request bodies to StringWithMatchingRules to support pact-xml ([a9fbb58](/../../commit/a9fbb58))
56
+ * add custom contract parsers to front of pact parsers list so that customised parsers are tried first ([babc319](/../../commit/babc319))
57
+
58
+
59
+ #### Bug Fixes
60
+
61
+ * show a more helpful error when attempting to parse a URI that is not a pact ([a8ba1ed](/../../commit/a8ba1ed))
62
+
63
+
64
+ <a name="v1.6.4"></a>
65
+ ### v1.6.4 (2018-07-14)
66
+
67
+
68
+ #### Bug Fixes
69
+
70
+ * correctly serialize query params that use a Pact.each_like in pact file ([b3414dd](/../../commit/b3414dd))
71
+
72
+
73
+ <a name="v1.6.3"></a>
74
+ ### v1.6.3 (2018-07-12)
75
+
76
+
77
+ #### Bug Fixes
78
+
79
+ * remove incorrect warning about ignoring unsupported matching rules for min => x ([50d5f6d](/../../commit/50d5f6d))
80
+ * serialize ArrayLike in query params without wrapping another array around it ([b4a9ec7](/../../commit/b4a9ec7))
81
+
82
+
83
+ <a name="v1.6.2"></a>
84
+ ### v1.6.2 (2018-05-31)
85
+
86
+
87
+ #### Bug Fixes
88
+
89
+ * **windows-path**
90
+ * prevent locale file paths to be parsed by URI to stop errors in windows paths like spaces in paths ([ecf64d6](/../../commit/ecf64d6))
91
+
92
+
93
+ <a name="v1.6.1"></a>
94
+ ### v1.6.1 (2018-05-21)
95
+
96
+
97
+ #### Bug Fixes
98
+
99
+ * correctly read local windows pact file paths with backslashes ([e27bd38](/../../commit/e27bd38))
100
+
101
+
102
+ <a name="v1.6.0"></a>
103
+ ### v1.6.0 (2018-04-03)
104
+
105
+
106
+ #### Features
107
+
108
+ * add support for writing v3 matching rules ([fc89696](/../../commit/fc89696))
109
+
110
+
111
+ <a name="v1.5.2"></a>
112
+ ### v1.5.2 (2018-03-23)
113
+
114
+ #### Bug Fixes
115
+
116
+ * remove include of pact matchers in query string ([c478dff](/../../commit/c478dff))
117
+
118
+
119
+ <a name="v1.5.1"></a>
120
+ ### v1.5.1 (2018-03-23)
121
+
122
+ #### Bug Fixes
123
+
124
+ * add missing require for pact matchers in query ([927d3b9](/../../commit/927d3b9))
125
+
126
+
127
+ <a name="v1.5.0"></a>
128
+ ### v1.5.0 (2018-03-23)
129
+
130
+ #### Features
131
+
132
+ * parse pacts without a specification version as v2 ([a69b5e6](/../../commit/a69b5e6))
133
+ * locate matching rules correctly for v3 pacts ([0f22db2](/../../commit/0f22db2))
134
+ * read matching rules from v3 format ([07013de](/../../commit/07013de))
135
+ * allow different consumer contract parsers to be registered ([531ab3a](/../../commit/531ab3a))
136
+ * update message classes to support pact-message ([2e48892](/../../commit/2e48892))
137
+ * add request and response to message ([93839cf](/../../commit/93839cf))
138
+
139
+ * **message contracts**
140
+ * dynamically mix in new and from_hash into Pact::Message ([c0c3ad5](/../../commit/c0c3ad5))
141
+ * read message pact into Ruby object ([6573bd4](/../../commit/6573bd4))
142
+
143
+
1
144
  <a name="v1.3.1"></a>
2
145
  ### v1.3.1 (2018-03-19)
3
146
 
@@ -1,9 +1,11 @@
1
1
  require 'pact/matchers/embedded_diff_formatter'
2
2
  require 'pact/matchers/unix_diff_formatter'
3
3
  require 'pact/matchers/list_diff_formatter'
4
+ require 'pact/matchers/multipart_form_diff_formatter'
4
5
  require 'pact/shared/json_differ'
5
6
  require 'pact/shared/text_differ'
6
7
  require 'pact/shared/form_differ'
8
+ require 'pact/shared/multipart_form_differ'
7
9
 
8
10
 
9
11
  module Pact
@@ -24,6 +26,7 @@ module Pact
24
26
  end
25
27
 
26
28
  DIFF_FORMATTER_REGISTRATIONS = [
29
+ [/multipart\/form-data/, Pact::Matchers::MultipartFormDiffFormatter],
27
30
  [/.*/, Pact::Matchers::UnixDiffFormatter],
28
31
  [NilMatcher, Pact::Matchers::UnixDiffFormatter]
29
32
  ]
@@ -31,6 +34,7 @@ module Pact
31
34
  DIFFERS = [
32
35
  [/json/, Pact::JsonDiffer],
33
36
  [/application\/x\-www\-form\-urlencoded/, Pact::FormDiffer],
37
+ [/multipart\/form-data/, Pact::MultipartFormDiffer],
34
38
  [NilMatcher, Pact::TextDiffer],
35
39
  [/.*/, Pact::TextDiffer]
36
40
  ]
@@ -10,9 +10,12 @@ require 'pact/consumer_contract/service_consumer'
10
10
  require 'pact/consumer_contract/service_provider'
11
11
  require 'pact/consumer_contract/interaction'
12
12
  require 'pact/consumer_contract/pact_file'
13
+ require 'pact/consumer_contract/http_consumer_contract_parser'
13
14
 
14
15
  module Pact
15
16
 
17
+ class UnrecognizePactFormatError < ::Pact::Error; end
18
+
16
19
  class ConsumerContract
17
20
 
18
21
  include SymbolizeKeys
@@ -29,13 +32,19 @@ module Pact
29
32
  @provider = attributes[:provider]
30
33
  end
31
34
 
35
+ def self.add_parser consumer_contract_parser
36
+ parsers.unshift(consumer_contract_parser)
37
+ end
38
+
39
+ def self.parsers
40
+ @parsers ||= [Pact::HttpConsumerContractParser.new]
41
+ end
42
+
32
43
  def self.from_hash(hash)
33
- hash = symbolize_keys(hash)
34
- new(
35
- :consumer => ServiceConsumer.from_hash(hash[:consumer]),
36
- :provider => ServiceProvider.from_hash(hash[:provider]),
37
- :interactions => hash[:interactions].collect { |h| Interaction.from_hash(h)}
38
- )
44
+ parsers.each do | parser |
45
+ return parser.call(hash) if parser.can_parse?(hash)
46
+ end
47
+ raise Pact::UnrecognizePactFormatError.new("This document does not use a recognised Pact format: #{hash}")
39
48
  end
40
49
 
41
50
  def self.from_json string
@@ -45,6 +54,8 @@ module Pact
45
54
 
46
55
  def self.from_uri uri, options = {}
47
56
  from_json(Pact::PactFile.read(uri, options))
57
+ rescue UnrecognizePactFormatError
58
+ raise Pact::UnrecognizePactFormatError.new("This document does not use a recognised Pact format. Please check that #{uri} is a valid pact file.")
48
59
  end
49
60
 
50
61
  def self.maintain_backwards_compatiblity_with_producer_keys string
@@ -54,9 +65,9 @@ module Pact
54
65
  def find_interaction criteria
55
66
  interactions = find_interactions criteria
56
67
  if interactions.size == 0
57
- raise "Could not find interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}."
68
+ raise Pact::Error.new("Could not find interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}.")
58
69
  elsif interactions.size > 1
59
- raise "Found more than 1 interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}."
70
+ raise Pact::Error.new("Found more than 1 interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}.")
60
71
  end
61
72
  interactions.first
62
73
  end
@@ -0,0 +1,37 @@
1
+ require 'pact/specification_version'
2
+
3
+ module Pact
4
+ class HttpConsumerContractParser
5
+ include SymbolizeKeys
6
+
7
+ def call(hash)
8
+ hash = symbolize_keys(hash)
9
+ v = pact_specification_version(hash)
10
+ options = { pact_specification_version: v }
11
+
12
+ if v.after? 3
13
+ Pact.configuration.error_stream.puts "WARN: This code only knows how to parse v3 pacts, attempting to parse v#{options[:pact_specification_version]} pact using v3 code."
14
+ end
15
+
16
+ interactions = hash[:interactions].collect { |hash| Interaction.from_hash(hash, options) }
17
+ ConsumerContract.new(
18
+ :consumer => ServiceConsumer.from_hash(hash[:consumer]),
19
+ :provider => ServiceProvider.from_hash(hash[:provider]),
20
+ :interactions => interactions
21
+ )
22
+ end
23
+
24
+ def pact_specification_version hash
25
+ # TODO handle all 3 ways of defining this...
26
+ # metadata.pactSpecificationVersion
27
+ maybe_pact_specification_version_1 = hash[:metadata] && hash[:metadata]['pactSpecification'] && hash[:metadata]['pactSpecification']['version']
28
+ maybe_pact_specification_version_2 = hash[:metadata] && hash[:metadata]['pactSpecificationVersion']
29
+ pact_specification_version = maybe_pact_specification_version_1 || maybe_pact_specification_version_2
30
+ pact_specification_version ? Pact::SpecificationVersion.new(pact_specification_version) : Pact::SpecificationVersion::NIL_VERSION
31
+ end
32
+
33
+ def can_parse?(hash)
34
+ hash.key?('interactions') || hash.key?(:interactions)
35
+ end
36
+ end
37
+ end
@@ -1,76 +1,77 @@
1
- require 'pact/consumer_contract/request'
2
- require 'pact/consumer_contract/response'
3
- require 'pact/symbolize_keys'
4
1
  require 'pact/shared/active_support_support'
5
- require 'pact/matching_rules'
6
- require 'pact/errors'
2
+ require 'pact/consumer_contract/interaction_parser'
7
3
 
8
4
  module Pact
9
- class Interaction
5
+ class Interaction
10
6
  include ActiveSupportSupport
11
- include SymbolizeKeys
12
7
 
13
- attr_accessor :description, :request, :response, :provider_state
8
+ attr_accessor :description, :request, :response, :provider_state, :provider_states
14
9
 
15
- def initialize attributes = {}
16
- @description = attributes[:description]
17
- @request = attributes[:request]
18
- @response = attributes[:response]
19
- @provider_state = attributes[:provider_state] || attributes[:providerState]
20
- end
10
+ def initialize attributes = {}
11
+ @description = attributes[:description]
12
+ @request = attributes[:request]
13
+ @response = attributes[:response]
14
+ @provider_state = attributes[:provider_state] || attributes[:providerState]
15
+ @provider_states = attributes[:provider_states]
16
+ end
21
17
 
22
- def self.from_hash hash
23
- request_hash = Pact::MatchingRules.merge(hash['request'], hash['request']['matchingRules'])
24
- request = Pact::Request::Expected.from_hash(request_hash)
25
- response_hash = Pact::MatchingRules.merge(hash['response'], hash['response']['matchingRules'])
26
- response = Pact::Response.from_hash(response_hash)
27
- new(symbolize_keys(hash).merge(request: request, response: response))
28
- end
18
+ def self.from_hash hash, options = {}
19
+ InteractionParser.call(hash, options)
20
+ end
29
21
 
30
- def to_hash
31
- {
32
- description: description,
33
- provider_state: provider_state,
34
- request: request.to_hash,
35
- response: response.to_hash
36
- }
37
- end
22
+ def to_hash
23
+ h = { description: description }
38
24
 
39
- def validate!
40
- raise Pact::InvalidInteractionError.new(self) unless description && request && response
25
+ if provider_states
26
+ h[:provider_states] = provider_states.collect(&:to_hash)
27
+ else
28
+ h[:provider_state] = provider_state
41
29
  end
42
30
 
43
- def matches_criteria? criteria
44
- criteria.each do | key, value |
45
- unless match_criterion self.send(key.to_s), value
46
- return false
47
- end
31
+ h[:request] = request.to_hash
32
+ h[:response] = response.to_hash
33
+ h
34
+ end
35
+
36
+ def http?
37
+ true
38
+ end
39
+
40
+ def validate!
41
+ raise Pact::InvalidInteractionError.new(self) unless description && request && response
42
+ end
43
+
44
+ def matches_criteria? criteria
45
+ criteria.each do | key, value |
46
+ unless match_criterion self.send(key.to_s), value
47
+ return false
48
48
  end
49
- true
50
49
  end
50
+ true
51
+ end
51
52
 
52
- def match_criterion target, criterion
53
- target == criterion || (criterion.is_a?(Regexp) && criterion.match(target))
54
- end
53
+ def match_criterion target, criterion
54
+ target == criterion || (criterion.is_a?(Regexp) && criterion.match(target))
55
+ end
55
56
 
56
- def == other
57
- other.is_a?(Interaction) && to_hash == other.to_hash
58
- end
57
+ def == other
58
+ other.is_a?(Interaction) && to_hash == other.to_hash
59
+ end
59
60
 
60
- def eq? other
61
- self == other
62
- end
61
+ def eq? other
62
+ self == other
63
+ end
63
64
 
64
- def description_with_provider_state_quoted
65
- provider_state ? "\"#{description}\" given \"#{provider_state}\"" : "\"#{description}\""
66
- end
65
+ def description_with_provider_state_quoted
66
+ provider_state ? "\"#{description}\" given \"#{provider_state}\"" : "\"#{description}\""
67
+ end
67
68
 
68
- def request_modifies_resource_without_checking_response_body?
69
- request.modifies_resource? && response.body_allows_any_value?
70
- end
69
+ def request_modifies_resource_without_checking_response_body?
70
+ request.modifies_resource? && response.body_allows_any_value?
71
+ end
71
72
 
72
- def to_s
73
- to_hash.to_s
74
- end
75
- end
73
+ def to_s
74
+ to_hash.to_s
75
+ end
76
+ end
76
77
  end
@@ -0,0 +1,23 @@
1
+ require 'pact/specification_version'
2
+ require 'pact/consumer_contract/interaction_v2_parser'
3
+ require 'pact/consumer_contract/interaction_v3_parser'
4
+
5
+ module Pact
6
+ class InteractionParser
7
+ def self.call hash, options = {}
8
+ pact_specification_version = options[:pact_specification_version] || Pact::SpecificationVersion::NIL_VERSION
9
+ case pact_specification_version.major
10
+ when nil, 0, 1, 2 then parse_v2_interaction(hash, pact_specification_version: pact_specification_version)
11
+ else parse_v3_interaction(hash, pact_specification_version: pact_specification_version)
12
+ end
13
+ end
14
+
15
+ def self.parse_v2_interaction hash, options
16
+ InteractionV2Parser.call(hash, options)
17
+ end
18
+
19
+ def self.parse_v3_interaction hash, options
20
+ InteractionV3Parser.call(hash, options)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ require 'pact/consumer_contract/request'
2
+ require 'pact/consumer_contract/response'
3
+ require 'pact/consumer_contract/provider_state'
4
+ require 'pact/symbolize_keys'
5
+ require 'pact/matching_rules'
6
+ require 'pact/errors'
7
+
8
+ module Pact
9
+ class InteractionV2Parser
10
+
11
+ include SymbolizeKeys
12
+
13
+ def self.call hash, options
14
+ request = parse_request(hash['request'], options)
15
+ response = parse_response(hash['response'], options)
16
+ provider_states = parse_provider_states(hash['providerState'] || hash['provider_state'])
17
+ Interaction.new(symbolize_keys(hash).merge(request: request, response: response, provider_states: provider_states))
18
+ end
19
+
20
+ def self.parse_request request_hash, options
21
+ request_hash = Pact::MatchingRules.merge(request_hash, request_hash['matchingRules'], options)
22
+ Pact::Request::Expected.from_hash(request_hash)
23
+ end
24
+
25
+ def self.parse_response response_hash, options
26
+ response_hash = Pact::MatchingRules.merge(response_hash, response_hash['matchingRules'], options)
27
+ Pact::Response.from_hash(response_hash)
28
+ end
29
+
30
+ def self.parse_provider_states provider_state_name
31
+ provider_state_name ? [Pact::ProviderState.new(provider_state_name)] : []
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,73 @@
1
+ require 'pact/consumer_contract/request'
2
+ require 'pact/consumer_contract/response'
3
+ require 'pact/consumer_contract/provider_state'
4
+ require 'pact/symbolize_keys'
5
+ require 'pact/matching_rules'
6
+ require 'pact/errors'
7
+ require 'pact/consumer_contract/string_with_matching_rules'
8
+
9
+ module Pact
10
+ class InteractionV3Parser
11
+
12
+ include SymbolizeKeys
13
+
14
+ def self.call hash, options
15
+ request = parse_request(hash['request'], options)
16
+ response = parse_response(hash['response'], options)
17
+ provider_states = parse_provider_states(hash['providerStates'])
18
+ provider_state = provider_states.any? ? provider_states.first.name : nil
19
+ if provider_states && provider_states.size > 1
20
+ Pact.configuration.error_stream.puts("WARN: Currently only 1 provider state is supported. Ignoring ")
21
+ end
22
+ Interaction.new(symbolize_keys(hash).merge(request: request, response: response, provider_states: provider_states, provider_state: provider_state))
23
+ end
24
+
25
+ def self.parse_request request_hash, options
26
+ request_matching_rules = request_hash['matchingRules'] || {}
27
+ if request_hash['body'].is_a?(String)
28
+ parse_request_with_string_body(request_hash, request_matching_rules['body'] || {}, options)
29
+ else
30
+ parse_request_with_non_string_body(request_hash, request_matching_rules, options)
31
+ end
32
+ end
33
+
34
+ def self.parse_response response_hash, options
35
+ response_matching_rules = response_hash['matchingRules'] || {}
36
+ if response_hash['body'].is_a?(String)
37
+ parse_response_with_string_body(response_hash, response_matching_rules['body'] || {}, options)
38
+ else
39
+ parse_response_with_non_string_body(response_hash, response_matching_rules, options)
40
+ end
41
+ end
42
+
43
+ def self.parse_request_with_non_string_body request_hash, request_matching_rules, options
44
+ request_hash = request_hash.keys.each_with_object({}) do | key, new_hash |
45
+ new_hash[key] = Pact::MatchingRules.merge(request_hash[key], request_matching_rules[key], options)
46
+ end
47
+ Pact::Request::Expected.from_hash(request_hash)
48
+ end
49
+
50
+ def self.parse_response_with_non_string_body response_hash, response_matching_rules, options
51
+ response_hash = response_hash.keys.each_with_object({}) do | key, new_hash |
52
+ new_hash[key] = Pact::MatchingRules.merge(response_hash[key], response_matching_rules[key], options)
53
+ end
54
+ Pact::Response.from_hash(response_hash)
55
+ end
56
+
57
+ def self.parse_request_with_string_body request_hash, request_matching_rules, options
58
+ string_with_matching_rules = StringWithMatchingRules.new(request_hash['body'], options[:pact_specification_version], request_matching_rules)
59
+ Pact::Request::Expected.from_hash(request_hash.merge('body' => string_with_matching_rules))
60
+ end
61
+
62
+ def self.parse_response_with_string_body response_hash, response_matching_rules, options
63
+ string_with_matching_rules = StringWithMatchingRules.new(response_hash['body'], options[:pact_specification_version], response_matching_rules)
64
+ Pact::Response.from_hash(response_hash.merge('body' => string_with_matching_rules))
65
+ end
66
+
67
+ def self.parse_provider_states provider_states
68
+ (provider_states || []).collect do | provider_state_hash |
69
+ Pact::ProviderState.new(provider_state_hash['name'], provider_state_hash['params'])
70
+ end
71
+ end
72
+ end
73
+ end
@@ -36,39 +36,25 @@ module Pact
36
36
  end
37
37
 
38
38
  def render_pact(uri_string, options)
39
- uri_obj = URI(uri_string)
40
- if uri_obj.userinfo
41
- options[:username] = uri_obj.user unless options[:username]
42
- options[:password] = uri_obj.password unless options[:password]
43
- end
44
- get(uri_obj, options)
39
+ local?(uri_string) ? get_local(uri_string, options) : get_remote_with_retry(uri_string, options)
45
40
  end
46
41
 
47
42
  private
48
43
 
49
- def get(uri, options)
50
- local?(uri) ? get_local(uri, options) : get_remote_with_retry(uri, options)
51
- end
52
-
53
44
  def local? uri
54
- !uri.host
45
+ !uri.start_with?("http://", "https://")
55
46
  end
56
47
 
57
- def get_local(uri, _)
58
- File.read uri.to_s
59
- end
60
-
61
- def get_remote(uri, options)
62
- request = Net::HTTP::Get.new(uri)
63
- request.basic_auth(options[:username], options[:password]) if options[:username]
64
- Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
65
- http.open_timeout = options[:open_timeout] || OPEN_TIMEOUT
66
- http.read_timeout = options[:read_timeout] || READ_TIMEOUT
67
- http.request(request)
68
- end
48
+ def get_local(filepath, _)
49
+ File.read windows_safe(filepath)
69
50
  end
70
51
 
71
- def get_remote_with_retry(uri, options)
52
+ def get_remote_with_retry(uri_string, options)
53
+ uri = URI(uri_string)
54
+ if uri.userinfo
55
+ options[:username] = uri.user unless options[:username]
56
+ options[:password] = uri.password unless options[:password]
57
+ end
72
58
  ((options[:retry_limit] || RETRY_LIMIT) + 1).times do |i|
73
59
  begin
74
60
  response = get_remote(uri, options)
@@ -89,6 +75,16 @@ module Pact
89
75
  end
90
76
  end
91
77
 
78
+ def get_remote(uri, options)
79
+ request = Net::HTTP::Get.new(uri)
80
+ request.basic_auth(options[:username], options[:password]) if options[:username]
81
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
82
+ http.open_timeout = options[:open_timeout] || OPEN_TIMEOUT
83
+ http.read_timeout = options[:read_timeout] || READ_TIMEOUT
84
+ http.request(request)
85
+ end
86
+ end
87
+
92
88
  def success?(response)
93
89
  response.code.to_i == 200
94
90
  end
@@ -104,5 +100,9 @@ module Pact
104
100
  def delay_retry(count)
105
101
  Kernel.sleep(2 ** count * 0.3)
106
102
  end
103
+
104
+ def windows_safe(uri)
105
+ uri.start_with?("http") ? uri : uri.gsub("\\", File::SEPARATOR)
106
+ end
107
107
  end
108
108
  end
@@ -0,0 +1,34 @@
1
+ module Pact
2
+ class ProviderState
3
+
4
+ attr_reader :name, :params
5
+
6
+ def initialize name, params = {}
7
+ @name = name
8
+ @params = params
9
+ end
10
+
11
+ def self.from_hash(hash)
12
+ new(hash["name"], hash["params"])
13
+ end
14
+
15
+ def ==(other)
16
+ other.is_a?(Pact::ProviderState) && other.name == self.name && other.params == self.params
17
+ end
18
+
19
+ def to_hash
20
+ {
21
+ "name" => name,
22
+ "params" => params
23
+ }
24
+ end
25
+
26
+ def to_json(opts = {})
27
+ as_json(opts).to_json(opts)
28
+ end
29
+
30
+ def as_json(opts = {})
31
+ to_hash
32
+ end
33
+ end
34
+ end
@@ -3,7 +3,6 @@ require 'pact/consumer_contract/query_string'
3
3
 
4
4
  module Pact
5
5
  class Query
6
-
7
6
  def self.create query
8
7
  if query.is_a? Hash
9
8
  Pact::QueryHash.new(query)
@@ -11,6 +10,5 @@ module Pact
11
10
  Pact::QueryString.new(query)
12
11
  end
13
12
  end
14
-
15
13
  end
16
14
  end