pact-mock_service 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/lib/pact/consumer/mock_service/set_location.rb +28 -0
  4. data/lib/pact/consumer_contract/consumer_contract_writer.rb +2 -2
  5. data/lib/pact/mock_service/app.rb +56 -0
  6. data/lib/pact/{consumer → mock_service}/app_manager.rb +4 -4
  7. data/lib/pact/{consumer/mock_service_client.rb → mock_service/client.rb} +2 -2
  8. data/lib/pact/mock_service/control_server/delegator.rb +1 -12
  9. data/lib/pact/mock_service/control_server/mock_service_creator.rb +1 -1
  10. data/lib/pact/mock_service/interactions/actual_interactions.rb +36 -0
  11. data/lib/pact/mock_service/interactions/candidate_interactions.rb +15 -0
  12. data/lib/pact/mock_service/interactions/expected_interactions.rb +18 -0
  13. data/lib/pact/mock_service/interactions/interaction_diff_message.rb +45 -0
  14. data/lib/pact/mock_service/interactions/interaction_mismatch.rb +74 -0
  15. data/lib/pact/mock_service/interactions/interactions_filter.rb +34 -0
  16. data/lib/pact/mock_service/interactions/verification.rb +48 -0
  17. data/lib/pact/mock_service/interactions/verified_interactions.rb +20 -0
  18. data/lib/pact/mock_service/logger.rb +27 -0
  19. data/lib/pact/mock_service/request_handlers/base_administration_request_handler.rb +42 -0
  20. data/lib/pact/mock_service/request_handlers/base_request_handler.rb +22 -0
  21. data/lib/pact/mock_service/request_handlers/index_get.rb +23 -0
  22. data/lib/pact/mock_service/request_handlers/interaction_delete.rb +36 -0
  23. data/lib/pact/mock_service/request_handlers/interaction_post.rb +41 -0
  24. data/lib/pact/mock_service/request_handlers/interaction_replay.rb +163 -0
  25. data/lib/pact/mock_service/request_handlers/interactions_put.rb +42 -0
  26. data/lib/pact/mock_service/request_handlers/log_get.rb +27 -0
  27. data/lib/pact/mock_service/request_handlers/missing_interactions_get.rb +33 -0
  28. data/lib/pact/mock_service/request_handlers/options.rb +42 -0
  29. data/lib/pact/mock_service/request_handlers/pact_post.rb +38 -0
  30. data/lib/pact/mock_service/request_handlers/verification_get.rb +72 -0
  31. data/lib/pact/mock_service/request_handlers.rb +40 -0
  32. data/lib/pact/mock_service/run.rb +14 -4
  33. data/lib/pact/mock_service/session.rb +70 -0
  34. data/lib/pact/mock_service/spawn.rb +26 -12
  35. data/lib/pact/mock_service/version.rb +1 -1
  36. data/lib/pact/mock_service.rb +2 -1
  37. metadata +29 -24
  38. data/lib/pact/consumer/interactions_filter.rb +0 -32
  39. data/lib/pact/consumer/mock_service/actual_interactions.rb +0 -34
  40. data/lib/pact/consumer/mock_service/app.rb +0 -58
  41. data/lib/pact/consumer/mock_service/candidate_interactions.rb +0 -13
  42. data/lib/pact/consumer/mock_service/expected_interactions.rb +0 -17
  43. data/lib/pact/consumer/mock_service/index_get.rb +0 -22
  44. data/lib/pact/consumer/mock_service/interaction_delete.rb +0 -39
  45. data/lib/pact/consumer/mock_service/interaction_mismatch.rb +0 -73
  46. data/lib/pact/consumer/mock_service/interaction_post.rb +0 -95
  47. data/lib/pact/consumer/mock_service/interaction_replay.rb +0 -162
  48. data/lib/pact/consumer/mock_service/log_get.rb +0 -28
  49. data/lib/pact/consumer/mock_service/missing_interactions_get.rb +0 -32
  50. data/lib/pact/consumer/mock_service/mock_service_administration_endpoint.rb +0 -40
  51. data/lib/pact/consumer/mock_service/options.rb +0 -43
  52. data/lib/pact/consumer/mock_service/pact_post.rb +0 -38
  53. data/lib/pact/consumer/mock_service/request_handlers.rb +0 -41
  54. data/lib/pact/consumer/mock_service/verification.rb +0 -46
  55. data/lib/pact/consumer/mock_service/verification_get.rb +0 -73
  56. data/lib/pact/consumer/mock_service/verified_interactions.rb +0 -18
  57. data/lib/pact/consumer/mock_service.rb +0 -43
@@ -0,0 +1,41 @@
1
+ require 'pact/mock_service/request_handlers/base_administration_request_handler'
2
+ require 'pact/mock_service/session'
3
+
4
+ module Pact
5
+ module MockService
6
+ module RequestHandlers
7
+ class InteractionPost < BaseAdministrationRequestHandler
8
+
9
+ def initialize name, logger, session
10
+ super name, logger
11
+ @session = session
12
+ end
13
+
14
+ def request_path
15
+ '/interactions'
16
+ end
17
+
18
+ def request_method
19
+ 'POST'
20
+ end
21
+
22
+ def respond env
23
+ request_body = env['rack.input'].string
24
+ interaction = Interaction.from_hash(JSON.load(request_body)) # Load creates the Pact::XXX classes
25
+
26
+ begin
27
+ session.add_expected_interaction interaction
28
+ [200, {}, ['Set interactions']]
29
+ rescue AlmostDuplicateInteractionError => e
30
+ [500, {}, e.message]
31
+ end
32
+
33
+ end
34
+
35
+ private
36
+
37
+ attr_accessor :session
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,163 @@
1
+ require 'pact/matchers'
2
+ require 'pact/consumer/request'
3
+ require 'pact/mock_service/interactions/interaction_mismatch'
4
+ require 'pact/consumer_contract'
5
+ require 'pact/mock_service/response_decorator'
6
+ require 'pact/mock_service/interaction_decorator'
7
+ require 'pact/mock_service/request_handlers/base_request_handler'
8
+
9
+ module Pact
10
+ module MockService
11
+ module RequestHandlers
12
+
13
+ module PrettyGenerate
14
+ #Doesn't seem to reliably pretty generate unless we go to JSON and back again :(
15
+ def pretty_generate object
16
+ JSON.pretty_generate(JSON.parse(object.to_json))
17
+ end
18
+ end
19
+
20
+ class InteractionReplay < BaseRequestHandler
21
+ include Pact::Matchers
22
+ include PrettyGenerate
23
+
24
+ attr_accessor :name, :logger, :expected_interactions, :actual_interactions, :verified_interactions
25
+
26
+ def initialize name, logger, session, cors_enabled=false
27
+ @name = name
28
+ @logger = logger
29
+ @expected_interactions = session.expected_interactions
30
+ @actual_interactions = session.actual_interactions
31
+ @verified_interactions = session.verified_interactions
32
+ @cors_enabled = cors_enabled
33
+ end
34
+
35
+ def match? env
36
+ true # default handler
37
+ end
38
+
39
+ def respond env
40
+ find_response request_as_hash_from(env)
41
+ end
42
+
43
+ private
44
+
45
+ def find_response request_hash
46
+ actual_request = Pact::Consumer::Request::Actual.from_hash(request_hash)
47
+ logger.info "Received request #{actual_request.method_and_path}"
48
+ logger.debug pretty_generate request_hash
49
+ candidate_interactions = expected_interactions.find_candidate_interactions actual_request
50
+ matching_interactions = candidate_interactions.matching_interactions actual_request
51
+
52
+ case matching_interactions.size
53
+ when 0 then handle_unrecognised_request actual_request, candidate_interactions
54
+ when 1 then handle_matched_interaction matching_interactions.first
55
+ else
56
+ handle_more_than_one_matching_interaction actual_request, matching_interactions
57
+ end
58
+ end
59
+
60
+ def handle_matched_interaction interaction
61
+ HandleMatchedInteraction.call(interaction, verified_interactions, actual_interactions, logger)
62
+ end
63
+
64
+ def handle_more_than_one_matching_interaction actual_request, matching_interactions
65
+ HandleMultipleInteractionsFound.call(actual_request, matching_interactions, logger)
66
+ end
67
+
68
+ def handle_unrecognised_request actual_request, candidate_interactions
69
+ HandleUnrecognisedInteraction.call(actual_request, candidate_interactions, actual_interactions, logger)
70
+ end
71
+
72
+ def logger_info_ap msg
73
+ logger.info msg
74
+ end
75
+
76
+ end
77
+
78
+ class HandleMultipleInteractionsFound
79
+
80
+ extend PrettyGenerate
81
+
82
+ def self.call actual_request, matching_interactions, logger
83
+ logger.error "Multiple interactions found for #{actual_request.method_and_path}:"
84
+ matching_interactions.each do | interaction |
85
+ logger.debug pretty_generate(Pact::MockService::InteractionDecorator.new(interaction))
86
+ end
87
+ response actual_request, matching_interactions
88
+ end
89
+
90
+ def self.response actual_request, matching_interactions
91
+ response = {
92
+ message: "Multiple interaction found for #{actual_request.method_and_path}",
93
+ matching_interactions: matching_interactions.collect{ | interaction | request_summary_for(interaction) }
94
+ }
95
+ [500, {'Content-Type' => 'application/json'}, [response.to_json]]
96
+ end
97
+
98
+ def self.request_summary_for interaction
99
+ summary = {:description => interaction.description}
100
+ summary[:provider_state] if interaction.provider_state
101
+ summary[:request] = Pact::MockService::RequestDecorator.new(interaction.request)
102
+ summary
103
+ end
104
+ end
105
+
106
+ class HandleUnrecognisedInteraction
107
+
108
+ def self.call actual_request, candidate_interactions, actual_interactions, logger
109
+ interaction_mismatch = interaction_mismatch(actual_request, candidate_interactions)
110
+ if candidate_interactions.any?
111
+ actual_interactions.register_interaction_mismatch interaction_mismatch
112
+ else
113
+ actual_interactions.register_unexpected_request actual_request
114
+ end
115
+ log interaction_mismatch, logger
116
+ response interaction_mismatch
117
+ end
118
+
119
+ def self.response interaction_mismatch
120
+ response = {
121
+ message: "No interaction found for #{interaction_mismatch.actual_request.method_and_path}",
122
+ interaction_diffs: interaction_mismatch.to_hash
123
+ }
124
+ [500, {'Content-Type' => 'application/json'}, [response.to_json]]
125
+ end
126
+
127
+ def self.interaction_mismatch actual_request, candidate_interactions
128
+ Pact::MockService::Interactions::InteractionMismatch.new(candidate_interactions, actual_request)
129
+ end
130
+
131
+ def self.log interaction_mismatch, logger
132
+ logger.error "No matching interaction found for #{interaction_mismatch.actual_request.method_and_path}"
133
+ logger.error 'Interaction diffs for that route:'
134
+ logger.error(interaction_mismatch.to_s)
135
+ end
136
+
137
+ end
138
+
139
+ class HandleMatchedInteraction
140
+
141
+ extend PrettyGenerate
142
+
143
+ def self.call interaction, verified_interactions, actual_interactions, logger
144
+ actual_interactions.register_matched interaction
145
+ verified_interactions << interaction
146
+ response = response_from(interaction.response)
147
+ logger.info "Found matching response for #{interaction.request.method_and_path}"
148
+ logger.debug pretty_generate(Pact::MockService::ResponseDecorator.new(interaction.response))
149
+ response
150
+ end
151
+
152
+ def self.response_from response
153
+ [response.status, (Pact::Reification.from_term(response.headers) || {}).to_hash, [render_body(Pact::Reification.from_term(response.body))]]
154
+ end
155
+
156
+ def self.render_body body
157
+ return '' unless body
158
+ body.kind_of?(String) ? body.force_encoding('utf-8') : body.to_json
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,42 @@
1
+ require 'pact/mock_service/request_handlers/base_administration_request_handler'
2
+ require 'pact/mock_service/interaction_decorator'
3
+ require 'pact/shared/json_differ'
4
+ require 'pact/mock_service/request_handlers/interaction_post' #Refactor diff message
5
+
6
+ module Pact
7
+ module MockService
8
+ module RequestHandlers
9
+ class InteractionsPut < BaseAdministrationRequestHandler
10
+
11
+ def initialize name, logger, session
12
+ super name, logger
13
+ @session = session
14
+ end
15
+
16
+ def request_path
17
+ '/interactions'
18
+ end
19
+
20
+ def request_method
21
+ 'PUT'
22
+ end
23
+
24
+ def respond env
25
+ request_body = JSON.load(env['rack.input'].string)
26
+ interactions = request_body['interactions'].collect { | hash | Interaction.from_hash(hash) }
27
+ begin
28
+ session.set_expected_interactions interactions
29
+ [200, {}, ['Set interactions']]
30
+ rescue AlmostDuplicateInteractionError => e
31
+ [500, {}, e.message]
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ attr_accessor :session
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+ require 'pact/mock_service/request_handlers/base_administration_request_handler'
2
+
3
+ module Pact
4
+ module MockService
5
+ module RequestHandlers
6
+ class LogGet < BaseAdministrationRequestHandler
7
+
8
+ def request_path
9
+ '/log'
10
+ end
11
+
12
+ def request_method
13
+ 'GET'
14
+ end
15
+
16
+ def respond env
17
+ logger.info "Debug message from client - #{message(env)}"
18
+ [200, {}, []]
19
+ end
20
+
21
+ def message env
22
+ params_hash(env).fetch('msg', [])[0]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ require 'pact/mock_service/request_handlers/base_administration_request_handler'
2
+ require 'pact/mock_service/interactions/verification'
3
+
4
+ module Pact
5
+ module MockService
6
+ module RequestHandlers
7
+
8
+ class MissingInteractionsGet < BaseAdministrationRequestHandler
9
+
10
+ def initialize name, logger, session
11
+ super name, logger
12
+ @expected_interactions = session.expected_interactions
13
+ @actual_interactions = session.actual_interactions
14
+ end
15
+
16
+ def request_path
17
+ '/interactions/missing'
18
+ end
19
+
20
+ def request_method
21
+ 'GET'
22
+ end
23
+
24
+ def respond env
25
+ verification = Pact::MockService::Interactions::Verification.new(@expected_interactions, @actual_interactions)
26
+ number_of_missing_interactions = verification.missing_interactions.size
27
+ logger.info "Number of missing interactions for mock \"#{name}\" = #{number_of_missing_interactions}"
28
+ [200, {}, [{size: number_of_missing_interactions}.to_json]]
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,42 @@
1
+ require 'pact/mock_service/request_handlers/base_request_handler'
2
+
3
+ module Pact
4
+ module MockService
5
+ module RequestHandlers
6
+
7
+ class Options < BaseRequestHandler
8
+
9
+ attr_reader :name, :logger, :cors_enabled
10
+
11
+ def initialize name, logger, cors_enabled
12
+ @name = name
13
+ @logger = logger
14
+ @cors_enabled = cors_enabled
15
+ end
16
+
17
+ def match? env
18
+ is_options_request?(env) && (cors_enabled || is_administration_request?(env))
19
+ end
20
+
21
+ def respond env
22
+ cors_headers = {
23
+ 'Access-Control-Allow-Origin' => env.fetch('HTTP_ORIGIN','*'),
24
+ 'Access-Control-Allow-Headers' => headers_from(env)["Access-Control-Request-Headers"],
25
+ 'Access-Control-Allow-Methods' => 'DELETE, POST, GET, HEAD, PUT, TRACE, CONNECT'
26
+ }
27
+ logger.info "Received OPTIONS request for mock service administration endpoint #{env['HTTP_ACCESS_CONTROL_REQUEST_METHOD']} #{env['PATH_INFO']}. Returning CORS headers: #{cors_headers.to_json}."
28
+ [200, cors_headers, []]
29
+ end
30
+
31
+ def is_options_request? env
32
+ env['REQUEST_METHOD'] == 'OPTIONS'
33
+ end
34
+
35
+ def is_administration_request? env
36
+ env["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"].match(/x-pact-mock-service/i)
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ require 'pact/mock_service/request_handlers/base_administration_request_handler'
2
+ require 'pact/consumer_contract/consumer_contract_writer'
3
+
4
+ module Pact
5
+ module MockService
6
+ module RequestHandlers
7
+ class PactPost < BaseAdministrationRequestHandler
8
+
9
+ attr_accessor :consumer_contract, :verified_interactions, :default_options
10
+
11
+ def initialize name, logger, session
12
+ super name, logger
13
+ @verified_interactions = session.verified_interactions
14
+ @default_options = {}
15
+ @default_options.merge!(session.consumer_contract_details)
16
+ end
17
+
18
+ def request_path
19
+ '/pact'
20
+ end
21
+
22
+ def request_method
23
+ 'POST'
24
+ end
25
+
26
+ def respond env
27
+ consumer_contract_details = JSON.parse(env['rack.input'].string, symbolize_names: true)
28
+ logger.info "Writing pact with details #{consumer_contract_details}"
29
+ consumer_contract_params = default_options.merge(consumer_contract_details.merge(interactions: verified_interactions))
30
+ consumer_contract_writer = ConsumerContractWriter.new(consumer_contract_params, logger)
31
+ json = consumer_contract_writer.write
32
+
33
+ [200, {'Content-Type' =>'application/json'}, [json]]
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,72 @@
1
+ require 'pact/mock_service/request_handlers/base_administration_request_handler'
2
+
3
+ module Pact
4
+ module MockService
5
+ module RequestHandlers
6
+ class VerificationGet < BaseAdministrationRequestHandler
7
+
8
+ def initialize name, logger, session
9
+ super name, logger
10
+ @expected_interactions = session.expected_interactions
11
+ @actual_interactions = session.actual_interactions
12
+ end
13
+
14
+ def request_path
15
+ '/interactions/verification'
16
+ end
17
+
18
+ def request_method
19
+ 'GET'
20
+ end
21
+
22
+ def respond env
23
+ verification = Pact::MockService::Interactions::Verification.new(expected_interactions, actual_interactions)
24
+ if verification.all_matched?
25
+ logger.info "Verifying - interactions matched for example \"#{example_description(env)}\""
26
+ [200, {'Content-Type' => 'text/plain'}, ['Interactions matched']]
27
+ else
28
+ error_message = FailureMessage.new(verification).to_s
29
+ logger.warn "Verifying - actual interactions do not match expected interactions for example \"#{example_description(env)}\". \n#{error_message}"
30
+ logger.warn error_message
31
+ [500, {'Content-Type' => 'text/plain'}, ["Actual interactions do not match expected interactions for mock #{name}.\n\n#{error_message}See #{logger.description} for details."]]
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ attr_accessor :expected_interactions, :actual_interactions
38
+
39
+ def example_description env
40
+ params_hash(env).fetch("example_description", [])[0]
41
+ end
42
+
43
+ class FailureMessage
44
+
45
+ def initialize verification
46
+ @verification = verification
47
+ end
48
+
49
+ def to_s
50
+ titles_and_summaries.collect do | title, summaries |
51
+ "#{title}:\n\t#{summaries.join("\n\t")}\n\n" if summaries.any?
52
+ end.compact.join
53
+
54
+ end
55
+
56
+ private
57
+
58
+ attr_reader :verification
59
+
60
+ def titles_and_summaries
61
+ {
62
+ "Incorrect requests" => verification.interaction_mismatches_summaries,
63
+ "Missing requests" => verification.missing_interactions_summaries,
64
+ "Unexpected requests" => verification.unexpected_requests_summaries,
65
+ }
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,40 @@
1
+ require 'pact/mock_service/request_handlers/interaction_post'
2
+ require 'pact/mock_service/request_handlers/interactions_put'
3
+ require 'pact/mock_service/request_handlers/index_get'
4
+ require 'pact/mock_service/request_handlers/interaction_delete'
5
+ require 'pact/mock_service/request_handlers/interaction_replay'
6
+ require 'pact/mock_service/request_handlers/log_get'
7
+ require 'pact/mock_service/request_handlers/options'
8
+ require 'pact/mock_service/request_handlers/missing_interactions_get'
9
+ require 'pact/mock_service/request_handlers/pact_post'
10
+ require 'pact/mock_service/request_handlers/verification_get'
11
+ require 'pact/consumer/request'
12
+ require 'pact/support'
13
+
14
+ module Pact
15
+ module MockService
16
+ module RequestHandlers
17
+
18
+ def self.new *args
19
+ App.new(*args)
20
+ end
21
+
22
+ class App < ::Rack::Cascade
23
+ def initialize name, logger, session, options
24
+ super [
25
+ Options.new(name, logger, options[:cors_enabled]),
26
+ MissingInteractionsGet.new(name, logger, session),
27
+ VerificationGet.new(name, logger, session),
28
+ InteractionPost.new(name, logger, session),
29
+ InteractionsPut.new(name, logger, session),
30
+ InteractionDelete.new(name, logger, session),
31
+ LogGet.new(name, logger),
32
+ PactPost.new(name, logger, session),
33
+ IndexGet.new(name, logger),
34
+ InteractionReplay.new(name, logger, session, options[:cors_enabled])
35
+ ]
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,5 +1,6 @@
1
1
  require 'find_a_port'
2
- require 'pact/consumer/mock_service'
2
+ require 'pact/mock_service/app'
3
+ require 'pact/consumer/mock_service/set_location'
3
4
 
4
5
  module Pact
5
6
  module MockService
@@ -14,7 +15,7 @@ module Pact
14
15
  end
15
16
 
16
17
  def call
17
- require 'pact/consumer/mock_service'
18
+ require 'pact/mock_service/app'
18
19
 
19
20
  trap(:INT) { call_shutdown_hooks }
20
21
  trap(:TERM) { call_shutdown_hooks }
@@ -28,7 +29,8 @@ module Pact
28
29
 
29
30
  def mock_service
30
31
  @mock_service ||= begin
31
- Pact::Consumer::MockService.new(service_options)
32
+ mock_service = Pact::MockService.new(service_options)
33
+ Pact::Consumer::SetLocation.new(mock_service, base_url)
32
34
  end
33
35
  end
34
36
 
@@ -63,7 +65,7 @@ module Pact
63
65
 
64
66
  def webbrick_opts
65
67
  opts = {
66
- :Port => options[:port] || FindAPort.available_port,
68
+ :Port => port,
67
69
  :AccessLog => []
68
70
  }
69
71
  opts.merge!(ssl_opts) if options[:ssl]
@@ -76,6 +78,14 @@ module Pact
76
78
  :SSLCertName => [ %w[CN localhost] ]
77
79
  }
78
80
  end
81
+
82
+ def port
83
+ @port ||= options[:port] || FindAPort.available_port
84
+ end
85
+
86
+ def base_url
87
+ options[:ssl] ? "https://localhost:#{port}" : "http://localhost:#{port}"
88
+ end
79
89
  end
80
90
  end
81
91
  end
@@ -0,0 +1,70 @@
1
+ require 'pact/mock_service/interactions/expected_interactions'
2
+ require 'pact/mock_service/interactions/actual_interactions'
3
+ require 'pact/mock_service/interactions/verified_interactions'
4
+ require 'pact/mock_service/interaction_decorator'
5
+ require 'pact/mock_service/interactions/interaction_diff_message'
6
+
7
+ module Pact
8
+ module MockService
9
+
10
+ class AlmostDuplicateInteractionError < StandardError; end
11
+
12
+ class Session
13
+
14
+ attr_reader :expected_interactions, :actual_interactions, :verified_interactions, :consumer_contract_details, :logger
15
+
16
+ def initialize options
17
+ @logger = options[:logger]
18
+ @expected_interactions = Interactions::ExpectedInteractions.new
19
+ @actual_interactions = Interactions::ActualInteractions.new
20
+ @verified_interactions = Interactions::VerifiedInteractions.new
21
+ @consumer_contract_details = {
22
+ pact_dir: options[:pact_dir],
23
+ consumer: {name: options[:consumer]},
24
+ provider: {name: options[:provider]},
25
+ interactions: verified_interactions
26
+ }
27
+ end
28
+
29
+ def set_expected_interactions interactions
30
+ clear_expected_and_actual_interactions
31
+ interactions.each do | interaction |
32
+ add_expected_interaction interaction
33
+ end
34
+ end
35
+
36
+ def clear_expected_and_actual_interactions
37
+ expected_interactions.clear
38
+ actual_interactions.clear
39
+ end
40
+
41
+ def add_expected_interaction interaction
42
+ if (previous_interaction = interaction_already_verified_with_same_description_and_provider_state_but_not_equal(interaction))
43
+ handle_almost_duplicate_interaction previous_interaction, interaction
44
+ else
45
+ really_add_expected_interaction interaction
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def really_add_expected_interaction interaction
52
+ expected_interactions << interaction
53
+ logger.info "Registered expected interaction #{interaction.request.method_and_path}"
54
+ logger.debug JSON.pretty_generate InteractionDecorator.new(interaction)
55
+ end
56
+
57
+ def handle_almost_duplicate_interaction previous_interaction, interaction
58
+ message = Interactions::InteractionDiffMessage.new(previous_interaction, interaction).to_s
59
+ logger.error message
60
+ raise AlmostDuplicateInteractionError, message
61
+ end
62
+
63
+ def interaction_already_verified_with_same_description_and_provider_state_but_not_equal interaction
64
+ other = verified_interactions.find_matching_description_and_provider_state interaction
65
+ other && other != interaction ? other : nil
66
+ end
67
+
68
+ end
69
+ end
70
+ end