pact-mock_service 0.2.4 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/pact/consumer/mock_service/set_location.rb +28 -0
- data/lib/pact/consumer_contract/consumer_contract_writer.rb +2 -2
- data/lib/pact/mock_service/app.rb +56 -0
- data/lib/pact/{consumer → mock_service}/app_manager.rb +4 -4
- data/lib/pact/{consumer/mock_service_client.rb → mock_service/client.rb} +2 -2
- data/lib/pact/mock_service/control_server/delegator.rb +1 -12
- data/lib/pact/mock_service/control_server/mock_service_creator.rb +1 -1
- data/lib/pact/mock_service/interactions/actual_interactions.rb +36 -0
- data/lib/pact/mock_service/interactions/candidate_interactions.rb +15 -0
- data/lib/pact/mock_service/interactions/expected_interactions.rb +18 -0
- data/lib/pact/mock_service/interactions/interaction_diff_message.rb +45 -0
- data/lib/pact/mock_service/interactions/interaction_mismatch.rb +74 -0
- data/lib/pact/mock_service/interactions/interactions_filter.rb +34 -0
- data/lib/pact/mock_service/interactions/verification.rb +48 -0
- data/lib/pact/mock_service/interactions/verified_interactions.rb +20 -0
- data/lib/pact/mock_service/logger.rb +27 -0
- data/lib/pact/mock_service/request_handlers/base_administration_request_handler.rb +42 -0
- data/lib/pact/mock_service/request_handlers/base_request_handler.rb +22 -0
- data/lib/pact/mock_service/request_handlers/index_get.rb +23 -0
- data/lib/pact/mock_service/request_handlers/interaction_delete.rb +36 -0
- data/lib/pact/mock_service/request_handlers/interaction_post.rb +41 -0
- data/lib/pact/mock_service/request_handlers/interaction_replay.rb +163 -0
- data/lib/pact/mock_service/request_handlers/interactions_put.rb +42 -0
- data/lib/pact/mock_service/request_handlers/log_get.rb +27 -0
- data/lib/pact/mock_service/request_handlers/missing_interactions_get.rb +33 -0
- data/lib/pact/mock_service/request_handlers/options.rb +42 -0
- data/lib/pact/mock_service/request_handlers/pact_post.rb +38 -0
- data/lib/pact/mock_service/request_handlers/verification_get.rb +72 -0
- data/lib/pact/mock_service/request_handlers.rb +40 -0
- data/lib/pact/mock_service/run.rb +14 -4
- data/lib/pact/mock_service/session.rb +70 -0
- data/lib/pact/mock_service/spawn.rb +26 -12
- data/lib/pact/mock_service/version.rb +1 -1
- data/lib/pact/mock_service.rb +2 -1
- metadata +29 -24
- data/lib/pact/consumer/interactions_filter.rb +0 -32
- data/lib/pact/consumer/mock_service/actual_interactions.rb +0 -34
- data/lib/pact/consumer/mock_service/app.rb +0 -58
- data/lib/pact/consumer/mock_service/candidate_interactions.rb +0 -13
- data/lib/pact/consumer/mock_service/expected_interactions.rb +0 -17
- data/lib/pact/consumer/mock_service/index_get.rb +0 -22
- data/lib/pact/consumer/mock_service/interaction_delete.rb +0 -39
- data/lib/pact/consumer/mock_service/interaction_mismatch.rb +0 -73
- data/lib/pact/consumer/mock_service/interaction_post.rb +0 -95
- data/lib/pact/consumer/mock_service/interaction_replay.rb +0 -162
- data/lib/pact/consumer/mock_service/log_get.rb +0 -28
- data/lib/pact/consumer/mock_service/missing_interactions_get.rb +0 -32
- data/lib/pact/consumer/mock_service/mock_service_administration_endpoint.rb +0 -40
- data/lib/pact/consumer/mock_service/options.rb +0 -43
- data/lib/pact/consumer/mock_service/pact_post.rb +0 -38
- data/lib/pact/consumer/mock_service/request_handlers.rb +0 -41
- data/lib/pact/consumer/mock_service/verification.rb +0 -46
- data/lib/pact/consumer/mock_service/verification_get.rb +0 -73
- data/lib/pact/consumer/mock_service/verified_interactions.rb +0 -18
- 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/
|
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/
|
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::
|
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 =>
|
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
|