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
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
|