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.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd03f421bbf55e3e676c14e1381c0b8276b65929
|
4
|
+
data.tar.gz: b083148cc1cc3d7ca79a2a42dc4b55b3b3129bf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d19c285a1b6c2d97ff25407ede34967c06471ae80f965ddc3cc1ca24e08b313bfaafca9ac7c49f711879e549fee6109aa653430bd063944e4d65c026d163237
|
7
|
+
data.tar.gz: ed483795cb21f664e482499f53b0fade46e774d978c051edbe906c9b4d5f464433523e6c22d17adcce9690c9a73a4fffde2cb5bba10d2cf4c84094e5050cab5e
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,12 @@ Do this to generate your change history
|
|
2
2
|
|
3
3
|
git log --pretty=format:' * %h - %s (%an, %ad)'
|
4
4
|
|
5
|
+
### 0.3.0 (4 Feb 2015)
|
6
|
+
|
7
|
+
* 60869be - Refactor - moving classes from Pact::Consumer module into Pact::MockService module. (Beth Skurrie, Wed Feb 4 19:28:54 2015 +1100)
|
8
|
+
* 4ada4f0 - Added endpoint for PUT /interactions. Allow javascript client to set up all interactions at once and avoid callback hell. (Beth Skurrie, Thu Jan 29 21:48:00 2015 +1100)
|
9
|
+
* a329f49 - Add X-Pact-Mock-Service-Location header to all responses from the MockService (Beth Skurrie, Sun Jan 25 09:00:20 2015 +1100)
|
10
|
+
|
5
11
|
### 0.2.4 (24 Jan 2015)
|
6
12
|
|
7
13
|
* b14050e - Add --ssl option for control server (Beth, Sat Jan 24 22:14:14 2015 +1100)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Pact
|
2
|
+
module Consumer
|
3
|
+
class SetLocation
|
4
|
+
|
5
|
+
LOCATION = 'X-Pact-Mock-Service-Location'.freeze
|
6
|
+
HTTP_X_PACT_MOCK_SERVICE = 'HTTP_X_PACT_MOCK_SERVICE'
|
7
|
+
|
8
|
+
def initialize app, base_url
|
9
|
+
@app = app
|
10
|
+
@location_header = {LOCATION => base_url}.freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
def call env
|
14
|
+
response = @app.call(env)
|
15
|
+
env[HTTP_X_PACT_MOCK_SERVICE] ? add_location_header_to_response(response) : response
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_location_header_to_response response
|
19
|
+
[response.first, response[1].merge(@location_header), response.last]
|
20
|
+
end
|
21
|
+
|
22
|
+
def shutdown
|
23
|
+
@app.shutdown
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'pact/consumer_contract'
|
2
|
-
require 'pact/
|
2
|
+
require 'pact/mock_service/interactions/interactions_filter'
|
3
3
|
require 'pact/consumer_contract/file_name'
|
4
4
|
require 'pact/consumer_contract/pact_file'
|
5
5
|
require 'pact/consumer_contract/consumer_contract_decorator'
|
@@ -63,7 +63,7 @@ module Pact
|
|
63
63
|
def interactions_for_new_consumer_contract
|
64
64
|
if updating?
|
65
65
|
merged_interactions = existing_interactions.dup
|
66
|
-
filter =
|
66
|
+
filter = Pact::MockService::Interactions::UpdatableInteractionsFilter.new(merged_interactions)
|
67
67
|
interactions.each {|i| filter << i }
|
68
68
|
merged_interactions
|
69
69
|
else
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'uri'
|
3
|
+
require 'json'
|
4
|
+
require 'pact/mock_service/logger'
|
5
|
+
require 'pact/consumer/mock_service/cors_origin_header_middleware'
|
6
|
+
require 'pact/mock_service/request_handlers'
|
7
|
+
require 'pact/consumer/mock_service/error_handler'
|
8
|
+
require 'pact/mock_service/session'
|
9
|
+
|
10
|
+
module Pact
|
11
|
+
module MockService
|
12
|
+
|
13
|
+
def self.new *args
|
14
|
+
App.new(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
class App
|
18
|
+
|
19
|
+
def initialize options = {}
|
20
|
+
@name = options.fetch(:name, "MockService")
|
21
|
+
logger = Logger.from_options(options)
|
22
|
+
@session = Session.new(options.merge(logger: logger))
|
23
|
+
request_handlers = RequestHandlers.new(@name, logger, @session, options)
|
24
|
+
@app = Rack::Builder.app do
|
25
|
+
use Pact::Consumer::MockService::ErrorHandler, logger
|
26
|
+
use Pact::Consumer::CorsOriginHeaderMiddleware, options[:cors_enabled]
|
27
|
+
run request_handlers
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def call env
|
32
|
+
@app.call env
|
33
|
+
end
|
34
|
+
|
35
|
+
def shutdown
|
36
|
+
write_pact_if_configured
|
37
|
+
end
|
38
|
+
|
39
|
+
def write_pact_if_configured
|
40
|
+
consumer_contract_writer = ConsumerContractWriter.new(@session.consumer_contract_details, StdoutLogger.new)
|
41
|
+
consumer_contract_writer.write if consumer_contract_writer.can_write?
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"#{@name} #{super.to_s}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Can't write to a file in a TRAP, might deadlock
|
50
|
+
class StdoutLogger
|
51
|
+
def info message
|
52
|
+
$stdout.puts "\n#{message}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -6,11 +6,11 @@ require 'find_a_port'
|
|
6
6
|
require 'pact/logging'
|
7
7
|
require 'pact/consumer/server'
|
8
8
|
require 'singleton'
|
9
|
-
require 'pact/
|
9
|
+
require 'pact/mock_service/app'
|
10
10
|
require 'find_a_port'
|
11
11
|
|
12
12
|
module Pact
|
13
|
-
module
|
13
|
+
module MockService
|
14
14
|
class AppManager
|
15
15
|
|
16
16
|
include Pact::Logging
|
@@ -27,7 +27,7 @@ module Pact
|
|
27
27
|
raise "Currently only http is supported" unless uri.scheme == 'http'
|
28
28
|
raise "Currently only services on localhost are supported" unless uri.host == 'localhost'
|
29
29
|
|
30
|
-
register(MockService.new(log_file: create_log_file(name), name: name, pact_dir: pact_dir), uri.port)
|
30
|
+
register(Pact::MockService.new(log_file: create_log_file(name), name: name, pact_dir: pact_dir), uri.port)
|
31
31
|
end
|
32
32
|
|
33
33
|
def register(app, port = FindAPort.available_port)
|
@@ -133,7 +133,7 @@ module Pact
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def is_a_mock_service?
|
136
|
-
app.is_a? MockService
|
136
|
+
app.is_a? Pact::MockService::App
|
137
137
|
end
|
138
138
|
|
139
139
|
def to_s
|
@@ -11,16 +11,13 @@ module Pact
|
|
11
11
|
|
12
12
|
HTTP_X_PACT_CONSUMER = 'HTTP_X_PACT_CONSUMER'.freeze
|
13
13
|
HTTP_X_PACT_PROVIDER = 'HTTP_X_PACT_PROVIDER'.freeze
|
14
|
-
LOCATION = 'X-Pact-Mock-Service-Location'.freeze
|
15
14
|
PACT_MOCK_SERVICE_HEADER = {'HTTP_X_PACT_MOCK_SERVICE' => 'true'}.freeze
|
16
15
|
NOT_FOUND_RESPONSE = [404, {}, []].freeze
|
17
16
|
|
18
|
-
def initialize app,
|
17
|
+
def initialize app, consumer_name, provider_name
|
19
18
|
@app = app
|
20
|
-
@base_url = base_url
|
21
19
|
@consumer_name = consumer_name
|
22
20
|
@provider_name = provider_name
|
23
|
-
@location_header = {LOCATION => @base_url}.freeze
|
24
21
|
end
|
25
22
|
|
26
23
|
def call env
|
@@ -39,16 +36,8 @@ module Pact
|
|
39
36
|
end
|
40
37
|
|
41
38
|
def delegate env
|
42
|
-
add_location_header_to_response(call_app(env))
|
43
|
-
end
|
44
|
-
|
45
|
-
def call_app env
|
46
39
|
@app.call(env.merge(PACT_MOCK_SERVICE_HEADER))
|
47
40
|
end
|
48
|
-
|
49
|
-
def add_location_header_to_response response
|
50
|
-
[response.first, response[1].merge(@location_header), response.last]
|
51
|
-
end
|
52
41
|
end
|
53
42
|
end
|
54
43
|
end
|
@@ -23,7 +23,7 @@ module Pact
|
|
23
23
|
provider_name = env['HTTP_X_PACT_PROVIDER']
|
24
24
|
port = FindAPort.available_port
|
25
25
|
mock_service = Pact::MockService::Spawn.(consumer_name, provider_name, port, options)
|
26
|
-
delegator = Delegator.new(mock_service,
|
26
|
+
delegator = Delegator.new(mock_service, consumer_name, provider_name)
|
27
27
|
@mock_services.add(delegator)
|
28
28
|
response = delegator.call(env)
|
29
29
|
response
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'pact/mock_service/interactions/candidate_interactions'
|
2
|
+
|
3
|
+
module Pact
|
4
|
+
module MockService
|
5
|
+
module Interactions
|
6
|
+
class ActualInteractions
|
7
|
+
|
8
|
+
attr_reader :matched_interactions, :interaction_mismatches, :unexpected_requests
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
clear
|
12
|
+
end
|
13
|
+
|
14
|
+
# For testing, sigh
|
15
|
+
def clear
|
16
|
+
@matched_interactions = []
|
17
|
+
@interaction_mismatches = []
|
18
|
+
@unexpected_requests = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def register_matched interaction
|
22
|
+
@matched_interactions << interaction
|
23
|
+
end
|
24
|
+
|
25
|
+
def register_unexpected_request request
|
26
|
+
@unexpected_requests << request
|
27
|
+
end
|
28
|
+
|
29
|
+
def register_interaction_mismatch interaction_mismatch
|
30
|
+
@interaction_mismatches << interaction_mismatch
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Pact
|
2
|
+
module MockService
|
3
|
+
module Interactions
|
4
|
+
class CandidateInteractions < Array
|
5
|
+
|
6
|
+
def matching_interactions actual_request
|
7
|
+
select do | candidate_interaction |
|
8
|
+
candidate_interaction.request.matches? actual_request
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'pact/mock_service/interactions/candidate_interactions'
|
2
|
+
|
3
|
+
module Pact
|
4
|
+
module MockService
|
5
|
+
module Interactions
|
6
|
+
class ExpectedInteractions < Array
|
7
|
+
|
8
|
+
def find_candidate_interactions actual_request
|
9
|
+
Pact::MockService::Interactions::CandidateInteractions.new(
|
10
|
+
select do | interaction |
|
11
|
+
interaction.request.matches_route? actual_request
|
12
|
+
end
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'pact/shared/json_differ'
|
2
|
+
require 'pact/mock_service/interaction_decorator'
|
3
|
+
|
4
|
+
module Pact
|
5
|
+
module MockService
|
6
|
+
module Interactions
|
7
|
+
class InteractionDiffMessage
|
8
|
+
|
9
|
+
def initialize previous_interaction, new_interaction
|
10
|
+
@previous_interaction = previous_interaction
|
11
|
+
@new_interaction = new_interaction
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"An interaction with same description (#{new_interaction.description.inspect}) and provider state (#{new_interaction.provider_state.inspect}) but a different #{differences} has already been used. Please use a different description or provider state."
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :previous_interaction, :new_interaction
|
21
|
+
|
22
|
+
def differences
|
23
|
+
diff = Pact::JsonDiffer.call(previous_interaction_hash, new_interaction_hash, allow_unexpected_keys: false)
|
24
|
+
diff.keys.collect do | parent_key |
|
25
|
+
diff[parent_key].keys.collect do | child_key |
|
26
|
+
"#{parent_key} #{child_key}"
|
27
|
+
end
|
28
|
+
end.flatten.join(", ").reverse.sub(",", "dna ").reverse
|
29
|
+
end
|
30
|
+
|
31
|
+
def previous_interaction_hash
|
32
|
+
raw_hash previous_interaction
|
33
|
+
end
|
34
|
+
|
35
|
+
def new_interaction_hash
|
36
|
+
raw_hash new_interaction
|
37
|
+
end
|
38
|
+
|
39
|
+
def raw_hash interaction
|
40
|
+
JSON.parse(Pact::MockService::InteractionDecorator.new(interaction).to_json)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Pact
|
2
|
+
module MockService
|
3
|
+
module Interactions
|
4
|
+
|
5
|
+
# expected interactions where the methods and paths match the actual request.
|
6
|
+
# This is used to display a helpful message to the user when a request
|
7
|
+
# comes in that doesn't match any of the expected interactions.
|
8
|
+
class InteractionMismatch
|
9
|
+
|
10
|
+
attr_accessor :candidate_interactions, :actual_request
|
11
|
+
|
12
|
+
# Assumes the method and path matches...
|
13
|
+
|
14
|
+
def initialize candidate_interactions, actual_request
|
15
|
+
@candidate_interactions = candidate_interactions
|
16
|
+
@actual_request = actual_request
|
17
|
+
@candiate_diffs = candidate_interactions.collect{ | candidate_interaction| CandidateDiff.new(candidate_interaction, actual_request)}
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
candiate_diffs.collect(&:to_hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
candiate_diffs.collect(&:to_s).join("\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
def short_summary
|
29
|
+
mismatched_attributes = candiate_diffs.collect(&:mismatched_attributes).flatten.uniq.join(", ").reverse.sub(",", "dna ").reverse #OMG what a hack!
|
30
|
+
actual_request.method_and_path + " (request #{mismatched_attributes} did not match)"
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_accessor :candiate_diffs
|
36
|
+
|
37
|
+
class CandidateDiff
|
38
|
+
|
39
|
+
attr_accessor :candidate_interaction, :actual_request
|
40
|
+
|
41
|
+
def initialize candidate_interaction, actual_request
|
42
|
+
@candidate_interaction = candidate_interaction
|
43
|
+
@actual_request = actual_request
|
44
|
+
end
|
45
|
+
|
46
|
+
def mismatched_attributes
|
47
|
+
diff.keys
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_hash
|
51
|
+
summary = {:description => candidate_interaction.description}
|
52
|
+
summary[:provider_state] = candidate_interaction.provider_state if candidate_interaction.provider_state
|
53
|
+
summary.merge(diff)
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
[
|
58
|
+
"Diff with interaction: #{candidate_interaction.description_with_provider_state_quoted}",
|
59
|
+
diff_formatter.call(diff, {colour: false})
|
60
|
+
].join("\n")
|
61
|
+
end
|
62
|
+
|
63
|
+
def diff_formatter
|
64
|
+
Pact.configuration.diff_formatter_for_content_type(candidate_interaction.request.content_type)
|
65
|
+
end
|
66
|
+
|
67
|
+
def diff
|
68
|
+
@diff ||= candidate_interaction.request.difference(actual_request)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#
|
2
|
+
# When running in pactfile_write_mode :overwrite, all interactions are cleared from the
|
3
|
+
# pact file, and all new interactions should be distinct (unique description and provider state).
|
4
|
+
# When running in pactfile_write_mode :update, an interaction with the same description
|
5
|
+
# and provider state as an existing one will just overwrite that one interaction.
|
6
|
+
#
|
7
|
+
|
8
|
+
module Pact
|
9
|
+
module MockService
|
10
|
+
module Interactions
|
11
|
+
|
12
|
+
#TODO: think of a better word than filter
|
13
|
+
class InteractionsFilter
|
14
|
+
def initialize interactions = []
|
15
|
+
@interactions = interactions
|
16
|
+
end
|
17
|
+
|
18
|
+
def index_of interaction
|
19
|
+
@interactions.find_index{ |i| i.matches_criteria?(description: interaction.description, provider_state: interaction.provider_state)}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class UpdatableInteractionsFilter < InteractionsFilter
|
24
|
+
def << interaction
|
25
|
+
if (ndx = index_of(interaction))
|
26
|
+
@interactions[ndx] = interaction
|
27
|
+
else
|
28
|
+
@interactions << interaction
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Pact
|
2
|
+
module MockService
|
3
|
+
module Interactions
|
4
|
+
class Verification
|
5
|
+
|
6
|
+
def initialize expected_interactions, actual_interactions
|
7
|
+
@expected_interactions = expected_interactions
|
8
|
+
@actual_interactions = actual_interactions
|
9
|
+
end
|
10
|
+
|
11
|
+
def all_matched?
|
12
|
+
interaction_diffs.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def interaction_diffs
|
16
|
+
{
|
17
|
+
:missing_interactions => missing_interactions_summaries,
|
18
|
+
:interaction_mismatches => interaction_mismatches_summaries,
|
19
|
+
:unexpected_requests => unexpected_requests_summaries
|
20
|
+
}.each_with_object({}) do | (key, value), hash |
|
21
|
+
hash[key] = value if value.any?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def missing_interactions_summaries
|
26
|
+
missing_interactions.collect(&:request).collect(&:method_and_path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def interaction_mismatches_summaries
|
30
|
+
actual_interactions.interaction_mismatches.collect(&:short_summary)
|
31
|
+
end
|
32
|
+
|
33
|
+
def unexpected_requests_summaries
|
34
|
+
actual_interactions.unexpected_requests.collect(&:method_and_path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def missing_interactions
|
38
|
+
expected_interactions - actual_interactions.matched_interactions - @actual_interactions.interaction_mismatches.collect(&:candidate_interactions).flatten
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
attr_reader :expected_interactions, :actual_interactions
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Pact
|
2
|
+
module MockService
|
3
|
+
module Interactions
|
4
|
+
class VerifiedInteractions < Array
|
5
|
+
|
6
|
+
def << interaction
|
7
|
+
unless find_matching_description_and_provider_state interaction
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_matching_description_and_provider_state interaction
|
13
|
+
find do |candidate_interaction|
|
14
|
+
candidate_interaction.matches_criteria?(description: interaction.description, provider_state: interaction.provider_state)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Pact
|
4
|
+
module MockService
|
5
|
+
class Logger < ::Logger
|
6
|
+
|
7
|
+
attr_reader :description
|
8
|
+
|
9
|
+
def initialize stream
|
10
|
+
super stream
|
11
|
+
@description = if stream.is_a? File
|
12
|
+
File.absolute_path(stream).gsub(Dir.pwd + "/", '')
|
13
|
+
else
|
14
|
+
"standard out/err"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.from_options options
|
19
|
+
log_stream = options[:log_file] || $stdout
|
20
|
+
logger = new log_stream
|
21
|
+
logger.formatter = options[:log_formatter] if options[:log_formatter]
|
22
|
+
logger.level = Pact.configuration.logger.level
|
23
|
+
logger
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'pact/consumer/mock_service/rack_request_helper'
|
2
|
+
require 'pact/mock_service/request_handlers/base_request_handler'
|
3
|
+
|
4
|
+
module Pact
|
5
|
+
module MockService
|
6
|
+
module RequestHandlers
|
7
|
+
class BaseAdministrationRequestHandler < BaseRequestHandler
|
8
|
+
|
9
|
+
attr_accessor :logger, :name
|
10
|
+
|
11
|
+
def initialize name, logger
|
12
|
+
@name = name
|
13
|
+
@logger = logger
|
14
|
+
end
|
15
|
+
|
16
|
+
def match? env
|
17
|
+
has_mock_service_header?(env) && path_matches?(env) && method_matches?(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def has_mock_service_header? env
|
21
|
+
env['HTTP_X_PACT_MOCK_SERVICE']
|
22
|
+
end
|
23
|
+
|
24
|
+
def path_matches? env
|
25
|
+
env['PATH_INFO'].chomp("/") == request_path
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_matches? env
|
29
|
+
env['REQUEST_METHOD'] == request_method
|
30
|
+
end
|
31
|
+
|
32
|
+
def request_path
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
def request_method
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'pact/consumer/mock_service/rack_request_helper'
|
2
|
+
|
3
|
+
module Pact
|
4
|
+
module MockService
|
5
|
+
module RequestHandlers
|
6
|
+
class BaseRequestHandler
|
7
|
+
|
8
|
+
NOT_FOUND_RESPONSE = [404, {}, []].freeze
|
9
|
+
|
10
|
+
include Pact::Consumer::RackRequestHelper
|
11
|
+
|
12
|
+
def match? env
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
def call env
|
17
|
+
match?(env) ? respond(env) : NOT_FOUND_RESPONSE
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'pact/mock_service/request_handlers/base_administration_request_handler'
|
2
|
+
|
3
|
+
module Pact
|
4
|
+
module MockService
|
5
|
+
module RequestHandlers
|
6
|
+
|
7
|
+
class IndexGet < BaseAdministrationRequestHandler
|
8
|
+
|
9
|
+
def request_path
|
10
|
+
''
|
11
|
+
end
|
12
|
+
|
13
|
+
def request_method
|
14
|
+
'GET'
|
15
|
+
end
|
16
|
+
|
17
|
+
def respond env
|
18
|
+
[200, {'Content-Type' => 'text/plain'}, ['Mock service running']]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'pact/mock_service/request_handlers/base_administration_request_handler'
|
2
|
+
|
3
|
+
module Pact
|
4
|
+
module MockService
|
5
|
+
module RequestHandlers
|
6
|
+
|
7
|
+
class InteractionDelete < BaseAdministrationRequestHandler
|
8
|
+
|
9
|
+
attr_accessor :session
|
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
|
+
'DELETE'
|
22
|
+
end
|
23
|
+
|
24
|
+
def respond env
|
25
|
+
session.clear_expected_and_actual_interactions
|
26
|
+
logger.info "Cleared interactions before example \"#{example_description(env)}\""
|
27
|
+
[200, {}, ['Deleted interactions']]
|
28
|
+
end
|
29
|
+
|
30
|
+
def example_description env
|
31
|
+
params_hash(env).fetch('example_description', [])[0]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|