pact-v2 2.0.0.pre.preview1
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 +7 -0
- data/CHANGELOG.md +1321 -0
- data/LICENSE.txt +23 -0
- data/bin/pact +4 -0
- data/lib/pact/cli/generate_pact_docs.rb +4 -0
- data/lib/pact/cli/run_pact_verification.rb +99 -0
- data/lib/pact/cli/spec_criteria.rb +26 -0
- data/lib/pact/cli.rb +45 -0
- data/lib/pact/consumer/configuration/configuration_extensions.rb +90 -0
- data/lib/pact/consumer/configuration/dsl.rb +11 -0
- data/lib/pact/consumer/configuration/mock_service.rb +112 -0
- data/lib/pact/consumer/configuration/service_consumer.rb +51 -0
- data/lib/pact/consumer/configuration/service_provider.rb +40 -0
- data/lib/pact/consumer/configuration.rb +10 -0
- data/lib/pact/consumer/consumer_contract_builder.rb +82 -0
- data/lib/pact/consumer/consumer_contract_builders.rb +10 -0
- data/lib/pact/consumer/interaction_builder.rb +45 -0
- data/lib/pact/consumer/rspec.rb +35 -0
- data/lib/pact/consumer/spec_hooks.rb +40 -0
- data/lib/pact/consumer/world.rb +37 -0
- data/lib/pact/consumer.rb +7 -0
- data/lib/pact/doc/README.md +13 -0
- data/lib/pact/doc/doc_file.rb +40 -0
- data/lib/pact/doc/generate.rb +11 -0
- data/lib/pact/doc/generator.rb +82 -0
- data/lib/pact/doc/interaction_view_model.rb +124 -0
- data/lib/pact/doc/markdown/consumer_contract_renderer.rb +68 -0
- data/lib/pact/doc/markdown/generator.rb +26 -0
- data/lib/pact/doc/markdown/index_renderer.rb +43 -0
- data/lib/pact/doc/markdown/interaction.erb +14 -0
- data/lib/pact/doc/markdown/interaction_renderer.rb +43 -0
- data/lib/pact/doc/sort_interactions.rb +16 -0
- data/lib/pact/hal/authorization_header_redactor.rb +32 -0
- data/lib/pact/hal/entity.rb +110 -0
- data/lib/pact/hal/http_client.rb +128 -0
- data/lib/pact/hal/link.rb +112 -0
- data/lib/pact/hal/non_json_entity.rb +28 -0
- data/lib/pact/hash_refinements.rb +17 -0
- data/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb +112 -0
- data/lib/pact/pact_broker/fetch_pacts.rb +103 -0
- data/lib/pact/pact_broker/notices.rb +34 -0
- data/lib/pact/pact_broker/pact_selection_description.rb +66 -0
- data/lib/pact/pact_broker.rb +25 -0
- data/lib/pact/project_root.rb +7 -0
- data/lib/pact/provider/configuration/configuration_extension.rb +69 -0
- data/lib/pact/provider/configuration/dsl.rb +18 -0
- data/lib/pact/provider/configuration/message_provider_dsl.rb +63 -0
- data/lib/pact/provider/configuration/pact_verification.rb +48 -0
- data/lib/pact/provider/configuration/pact_verification_from_broker.rb +126 -0
- data/lib/pact/provider/configuration/service_provider_config.rb +32 -0
- data/lib/pact/provider/configuration/service_provider_dsl.rb +107 -0
- data/lib/pact/provider/configuration.rb +7 -0
- data/lib/pact/provider/context.rb +0 -0
- data/lib/pact/provider/help/console_text.rb +76 -0
- data/lib/pact/provider/help/content.rb +38 -0
- data/lib/pact/provider/help/pact_diff.rb +43 -0
- data/lib/pact/provider/help/prompt_text.rb +49 -0
- data/lib/pact/provider/help/write.rb +56 -0
- data/lib/pact/provider/matchers/messages.rb +66 -0
- data/lib/pact/provider/pact_helper_locator.rb +24 -0
- data/lib/pact/provider/pact_source.rb +40 -0
- data/lib/pact/provider/pact_spec_runner.rb +188 -0
- data/lib/pact/provider/pact_uri.rb +55 -0
- data/lib/pact/provider/pact_verification.rb +17 -0
- data/lib/pact/provider/print_missing_provider_states.rb +35 -0
- data/lib/pact/provider/request.rb +77 -0
- data/lib/pact/provider/rspec/backtrace_formatter.rb +43 -0
- data/lib/pact/provider/rspec/calculate_exit_code.rb +18 -0
- data/lib/pact/provider/rspec/custom_options_file +0 -0
- data/lib/pact/provider/rspec/formatter_rspec_2.rb +76 -0
- data/lib/pact/provider/rspec/formatter_rspec_3.rb +195 -0
- data/lib/pact/provider/rspec/json_formatter.rb +100 -0
- data/lib/pact/provider/rspec/matchers.rb +80 -0
- data/lib/pact/provider/rspec/pact_broker_formatter.rb +76 -0
- data/lib/pact/provider/rspec.rb +234 -0
- data/lib/pact/provider/state/provider_state.rb +180 -0
- data/lib/pact/provider/state/provider_state_configured_modules.rb +15 -0
- data/lib/pact/provider/state/provider_state_manager.rb +42 -0
- data/lib/pact/provider/state/provider_state_proxy.rb +39 -0
- data/lib/pact/provider/state/set_up.rb +13 -0
- data/lib/pact/provider/state/tear_down.rb +13 -0
- data/lib/pact/provider/test_methods.rb +77 -0
- data/lib/pact/provider/verification_report.rb +36 -0
- data/lib/pact/provider/verification_results/create.rb +88 -0
- data/lib/pact/provider/verification_results/publish.rb +143 -0
- data/lib/pact/provider/verification_results/publish_all.rb +50 -0
- data/lib/pact/provider/verification_results/verification_result.rb +40 -0
- data/lib/pact/provider/world.rb +50 -0
- data/lib/pact/provider.rb +3 -0
- data/lib/pact/retry.rb +37 -0
- data/lib/pact/tasks/task_helper.rb +62 -0
- data/lib/pact/tasks/verification_task.rb +95 -0
- data/lib/pact/tasks.rb +2 -0
- data/lib/pact/templates/help.erb +22 -0
- data/lib/pact/templates/provider_state.erb +14 -0
- data/lib/pact/utils/metrics.rb +100 -0
- data/lib/pact/utils/string.rb +35 -0
- data/lib/pact/v2/configuration.rb +23 -0
- data/lib/pact/v2/consumer/grpc_interaction_builder.rb +187 -0
- data/lib/pact/v2/consumer/http_interaction_builder.rb +163 -0
- data/lib/pact/v2/consumer/interaction_contents.rb +54 -0
- data/lib/pact/v2/consumer/message_interaction_builder.rb +280 -0
- data/lib/pact/v2/consumer/mock_server.rb +99 -0
- data/lib/pact/v2/consumer/pact_config/base.rb +24 -0
- data/lib/pact/v2/consumer/pact_config/grpc.rb +26 -0
- data/lib/pact/v2/consumer/pact_config/http.rb +55 -0
- data/lib/pact/v2/consumer/pact_config/message.rb +17 -0
- data/lib/pact/v2/consumer/pact_config.rb +24 -0
- data/lib/pact/v2/consumer.rb +8 -0
- data/lib/pact/v2/matchers/base.rb +67 -0
- data/lib/pact/v2/matchers/v1/equality.rb +19 -0
- data/lib/pact/v2/matchers/v2/regex.rb +19 -0
- data/lib/pact/v2/matchers/v2/type.rb +17 -0
- data/lib/pact/v2/matchers/v3/boolean.rb +17 -0
- data/lib/pact/v2/matchers/v3/date.rb +18 -0
- data/lib/pact/v2/matchers/v3/date_time.rb +18 -0
- data/lib/pact/v2/matchers/v3/decimal.rb +17 -0
- data/lib/pact/v2/matchers/v3/each.rb +42 -0
- data/lib/pact/v2/matchers/v3/include.rb +17 -0
- data/lib/pact/v2/matchers/v3/integer.rb +17 -0
- data/lib/pact/v2/matchers/v3/number.rb +17 -0
- data/lib/pact/v2/matchers/v3/time.rb +18 -0
- data/lib/pact/v2/matchers/v4/each_key.rb +26 -0
- data/lib/pact/v2/matchers/v4/each_key_value.rb +32 -0
- data/lib/pact/v2/matchers/v4/each_value.rb +33 -0
- data/lib/pact/v2/matchers/v4/not_empty.rb +17 -0
- data/lib/pact/v2/matchers.rb +94 -0
- data/lib/pact/v2/native/blocking_verifier.rb +17 -0
- data/lib/pact/v2/native/logger.rb +25 -0
- data/lib/pact/v2/provider/async_message_verifier.rb +28 -0
- data/lib/pact/v2/provider/base_verifier.rb +242 -0
- data/lib/pact/v2/provider/grpc_verifier.rb +38 -0
- data/lib/pact/v2/provider/gruf_server.rb +75 -0
- data/lib/pact/v2/provider/http_server.rb +79 -0
- data/lib/pact/v2/provider/http_verifier.rb +43 -0
- data/lib/pact/v2/provider/message_provider_servlet.rb +79 -0
- data/lib/pact/v2/provider/mixed_verifier.rb +22 -0
- data/lib/pact/v2/provider/pact_broker_proxy.rb +71 -0
- data/lib/pact/v2/provider/pact_broker_proxy_runner.rb +77 -0
- data/lib/pact/v2/provider/pact_config/async.rb +29 -0
- data/lib/pact/v2/provider/pact_config/base.rb +101 -0
- data/lib/pact/v2/provider/pact_config/grpc.rb +26 -0
- data/lib/pact/v2/provider/pact_config/http.rb +27 -0
- data/lib/pact/v2/provider/pact_config/mixed.rb +39 -0
- data/lib/pact/v2/provider/pact_config.rb +26 -0
- data/lib/pact/v2/provider/provider_server_runner.rb +89 -0
- data/lib/pact/v2/provider/provider_state_configuration.rb +32 -0
- data/lib/pact/v2/provider/provider_state_servlet.rb +86 -0
- data/lib/pact/v2/provider.rb +8 -0
- data/lib/pact/v2/railtie.rb +13 -0
- data/lib/pact/v2/rspec/support/pact_consumer_helpers.rb +80 -0
- data/lib/pact/v2/rspec/support/pact_message_helpers.rb +42 -0
- data/lib/pact/v2/rspec/support/pact_provider_helpers.rb +129 -0
- data/lib/pact/v2/rspec/support/waterdrop/pact_waterdrop_client.rb +27 -0
- data/lib/pact/v2/rspec/support/webmock/webmock_helpers.rb +30 -0
- data/lib/pact/v2/rspec.rb +17 -0
- data/lib/pact/v2/tasks/pact.rake +13 -0
- data/lib/pact/v2/version.rb +8 -0
- data/lib/pact/v2.rb +71 -0
- data/lib/pact/version.rb +4 -0
- data/lib/pact.rb +13 -0
- data/lib/tasks/pact.rake +34 -0
- data/pact.gemspec +106 -0
- metadata +529 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2013 REA Group Ltd
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
data/bin/pact
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'pact/cli/spec_criteria'
|
2
|
+
|
3
|
+
module Pact
|
4
|
+
module Cli
|
5
|
+
class RunPactVerification
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize options
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.call options
|
13
|
+
new(options).call
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
configure_output
|
18
|
+
initialize_rspec
|
19
|
+
setup_load_path
|
20
|
+
load_pact_helper
|
21
|
+
run_specs
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def initialize_rspec
|
27
|
+
# With RSpec3, if the pact_helper loads a library that adds its own formatter before we set one,
|
28
|
+
# we will get a ProgressFormatter too, and get little dots sprinkled throughout our output.
|
29
|
+
# Load a NilFormatter here to prevent that.
|
30
|
+
require 'rspec'
|
31
|
+
require 'pact/rspec'
|
32
|
+
::RSpec.configuration.add_formatter Pact::RSpec.formatter_class.const_get('NilFormatter')
|
33
|
+
end
|
34
|
+
|
35
|
+
def setup_load_path
|
36
|
+
require 'pact/provider/pact_spec_runner'
|
37
|
+
lib = File.join(Dir.pwd, "lib") # Assume we are running from within the project root. RSpec is smarter about this.
|
38
|
+
spec = File.join(Dir.pwd, "spec")
|
39
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
40
|
+
$LOAD_PATH.unshift(spec) if Dir.exist?(spec) && !$LOAD_PATH.include?(spec)
|
41
|
+
end
|
42
|
+
|
43
|
+
def load_pact_helper
|
44
|
+
load options[:pact_helper]
|
45
|
+
end
|
46
|
+
|
47
|
+
def run_specs
|
48
|
+
exit_code = if options[:pact_uri].is_a?(String)
|
49
|
+
run_with_pact_url_string
|
50
|
+
elsif options[:pact_uri]
|
51
|
+
run_with_pact_uri_object # from pact-provider-verifier
|
52
|
+
else
|
53
|
+
run_with_configured_pacts_from_pact_helper
|
54
|
+
end
|
55
|
+
exit exit_code
|
56
|
+
end
|
57
|
+
|
58
|
+
def run_with_pact_url_string
|
59
|
+
pact_repository_uri_options = {}
|
60
|
+
pact_repository_uri_options[:username] = ENV['PACT_BROKER_USERNAME'] if ENV['PACT_BROKER_USERNAME']
|
61
|
+
pact_repository_uri_options[:password] = ENV['PACT_BROKER_PASSWORD'] if ENV['PACT_BROKER_PASSWORD']
|
62
|
+
pact_repository_uri_options[:token] = ENV['PACT_BROKER_TOKEN']
|
63
|
+
pact_repository_uri_options[:username] = options[:pact_broker_username] if options[:pact_broker_username]
|
64
|
+
pact_repository_uri_options[:password] = options[:pact_broker_password] if options[:pact_broker_password]
|
65
|
+
pact_uri = ::Pact::Provider::PactURI.new(options[:pact_uri], pact_repository_uri_options)
|
66
|
+
Pact::Provider::PactSpecRunner.new([pact_uri], pact_spec_options).run
|
67
|
+
end
|
68
|
+
|
69
|
+
def run_with_pact_uri_object
|
70
|
+
Pact::Provider::PactSpecRunner.new([options[:pact_uri]], pact_spec_options).run
|
71
|
+
end
|
72
|
+
|
73
|
+
def run_with_configured_pacts_from_pact_helper
|
74
|
+
pact_urls = Pact.provider_world.pact_urls
|
75
|
+
Pact::Provider::PactSpecRunner.new(pact_urls, pact_spec_options).run
|
76
|
+
end
|
77
|
+
|
78
|
+
def pact_spec_options
|
79
|
+
{
|
80
|
+
full_backtrace: options[:backtrace],
|
81
|
+
verbose: options[:verbose] || ENV['VERBOSE'] == 'true',
|
82
|
+
criteria: SpecCriteria.call(options),
|
83
|
+
format: options[:format],
|
84
|
+
out: options[:out],
|
85
|
+
ignore_failures: options[:ignore_failures],
|
86
|
+
request_customizer: options[:request_customizer]
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def configure_output
|
91
|
+
if options[:format] == 'json' && !options[:out]
|
92
|
+
# Don't want to mess up the JSON parsing with messages to stdout, so send it to stderr
|
93
|
+
require 'pact/configuration'
|
94
|
+
Pact.configuration.output_stream = Pact.configuration.error_stream
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Pact
|
2
|
+
module Cli
|
3
|
+
class SpecCriteria
|
4
|
+
|
5
|
+
def self.call options
|
6
|
+
criteria = {}
|
7
|
+
|
8
|
+
criteria[:description] = Regexp.new(options[:description]) if options[:description]
|
9
|
+
criteria[:_id] = options[:pact_broker_interaction_id] if options[:pact_broker_interaction_id]
|
10
|
+
criteria[:index] = options[:interaction_index] if options[:interaction_index]
|
11
|
+
|
12
|
+
provider_state = options[:provider_state]
|
13
|
+
|
14
|
+
if provider_state
|
15
|
+
if provider_state.length == 0
|
16
|
+
criteria[:provider_state] = nil #Allow PACT_PROVIDER_STATE="" to mean no provider state
|
17
|
+
else
|
18
|
+
criteria[:provider_state] = Regexp.new(provider_state)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
criteria
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/pact/cli.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'pact/consumer/configuration'
|
3
|
+
require 'pact/provider/configuration'
|
4
|
+
|
5
|
+
module Pact
|
6
|
+
class CLI < Thor
|
7
|
+
def self.exit_on_failure? # Thor 1.0 deprecation guard
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'verify', "Verify a pact"
|
12
|
+
method_option :pact_helper, aliases: "-h", desc: "Pact helper file", :required => true
|
13
|
+
method_option :pact_uri, aliases: "-p", desc: "Pact URI"
|
14
|
+
method_option :ignore_failures, type: :boolean, default: false, desc: "Process will always exit with exit code 0", hide: true
|
15
|
+
method_option :pact_broker_username, aliases: "-u", desc: "Pact broker user name"
|
16
|
+
method_option :pact_broker_password, aliases: "-w", desc: "Pact broker password"
|
17
|
+
method_option :pact_broker_token, aliases: "-k", desc: "Pact broker token"
|
18
|
+
method_option :backtrace, aliases: "-b", desc: "Show full backtrace", :default => false, :type => :boolean
|
19
|
+
method_option :verbose, aliases: "-v", desc: "Show verbose HTTP logging", :default => false, :type => :boolean
|
20
|
+
method_option :interactions_replay_order, aliases: "-o",
|
21
|
+
desc: "Interactions replay order: randomised or recorded (default)",
|
22
|
+
default: Pact.configuration.interactions_replay_order
|
23
|
+
method_option :description, aliases: "-d", desc: "Interaction description filter"
|
24
|
+
method_option :provider_state, aliases: "-s", desc: "Provider state filter"
|
25
|
+
method_option :interaction_index, type: :numeric, desc: "Index filter"
|
26
|
+
method_option :pact_broker_interaction_id, desc: "Pact Broker interaction ID filter"
|
27
|
+
method_option :format, aliases: "-f", banner: "FORMATTER", desc: "RSpec formatter. Defaults to custom Pact formatter. [j]son may also be used."
|
28
|
+
method_option :out, aliases: "-o", banner: "FILE", desc: "Write output to a file instead of $stdout."
|
29
|
+
|
30
|
+
def verify
|
31
|
+
require 'pact/cli/run_pact_verification'
|
32
|
+
Cli::RunPactVerification.call(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'docs', "Generate Pact documentation in markdown"
|
36
|
+
method_option :pact_dir, desc: "Directory containing the pacts", default: Pact.configuration.pact_dir
|
37
|
+
method_option :doc_dir, desc: "Documentation directory", default: Pact.configuration.doc_dir
|
38
|
+
|
39
|
+
def docs
|
40
|
+
require 'pact/cli/generate_pact_docs'
|
41
|
+
require 'pact/doc/generator'
|
42
|
+
Pact::Doc::Generate.call(options[:pact_dir], options[:doc_dir], [Pact::Doc::Markdown::Generator])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'pact/configuration'
|
2
|
+
require 'pact/doc/markdown/generator'
|
3
|
+
|
4
|
+
module Pact
|
5
|
+
module Consumer
|
6
|
+
module Configuration
|
7
|
+
|
8
|
+
module ConfigurationExtensions
|
9
|
+
|
10
|
+
DOC_GENERATORS = { markdown: Pact::Doc::Markdown::Generator }
|
11
|
+
|
12
|
+
def doc_dir
|
13
|
+
@doc_dir ||= File.expand_path("./doc/pacts")
|
14
|
+
end
|
15
|
+
|
16
|
+
def doc_dir= doc_dir
|
17
|
+
@doc_dir = doc_dir
|
18
|
+
end
|
19
|
+
|
20
|
+
def reports_dir
|
21
|
+
@reports_dir ||= default_reports_dir
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_reports_dir
|
25
|
+
File.expand_path("./reports/pacts")
|
26
|
+
end
|
27
|
+
|
28
|
+
def reports_dir= reports_dir
|
29
|
+
@reports_dir = reports_dir
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_provider_verification &block
|
33
|
+
provider_verifications << block
|
34
|
+
end
|
35
|
+
|
36
|
+
def provider_verifications
|
37
|
+
@provider_verifications ||= []
|
38
|
+
end
|
39
|
+
|
40
|
+
def doc_generator= doc_generator
|
41
|
+
add_doc_generator doc_generator
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_doc_generator doc_generator
|
45
|
+
doc_generators << begin
|
46
|
+
if DOC_GENERATORS[doc_generator]
|
47
|
+
DOC_GENERATORS[doc_generator]
|
48
|
+
elsif doc_generator.respond_to?(:call)
|
49
|
+
doc_generator
|
50
|
+
else
|
51
|
+
raise "doc_generator needs to respond to call, or be in the preconfigured list: #{DOC_GENERATORS.keys}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def doc_generators
|
57
|
+
@doc_generators ||= []
|
58
|
+
end
|
59
|
+
|
60
|
+
def pactfile_write_mode
|
61
|
+
@pactfile_write_mode ||= :overwrite
|
62
|
+
if @pactfile_write_mode == :smart
|
63
|
+
is_rake_running? ? :overwrite : :update
|
64
|
+
else
|
65
|
+
@pactfile_write_mode
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def pactfile_write_mode= pactfile_write_mode
|
70
|
+
@pactfile_write_mode = pactfile_write_mode
|
71
|
+
end
|
72
|
+
|
73
|
+
def pactfile_write_order
|
74
|
+
@pactfile_write_order ||= :chronological #or :alphabetical
|
75
|
+
end
|
76
|
+
|
77
|
+
def pactfile_write_order= pactfile_write_order
|
78
|
+
@pactfile_write_order = pactfile_write_order.to_sym
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
#Would love a better way of determining this! It sure won't work on windows.
|
84
|
+
def is_rake_running?
|
85
|
+
`ps -ef | grep rake | grep #{Process.ppid} | grep -v 'grep'`.size > 0
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'pact/mock_service/version'
|
2
|
+
require 'pact/mock_service/app_manager'
|
3
|
+
require 'pact/consumer/consumer_contract_builder'
|
4
|
+
require 'pact/consumer/consumer_contract_builders'
|
5
|
+
require 'pact/consumer/world'
|
6
|
+
|
7
|
+
module Pact
|
8
|
+
module Consumer
|
9
|
+
module Configuration
|
10
|
+
class MockService
|
11
|
+
|
12
|
+
extend Pact::DSL
|
13
|
+
|
14
|
+
attr_accessor :port, :host, :standalone, :verify, :provider_name, :consumer_name, :pact_specification_version
|
15
|
+
|
16
|
+
def initialize name, consumer_name, provider_name
|
17
|
+
@name = name
|
18
|
+
@consumer_name = consumer_name
|
19
|
+
@provider_name = provider_name
|
20
|
+
@port = nil
|
21
|
+
@host = "localhost"
|
22
|
+
@standalone = false
|
23
|
+
@verify = true
|
24
|
+
@pact_specification_version = '2'
|
25
|
+
@finalized = false
|
26
|
+
end
|
27
|
+
|
28
|
+
dsl do
|
29
|
+
def port port
|
30
|
+
self.port = port
|
31
|
+
end
|
32
|
+
|
33
|
+
def host host
|
34
|
+
self.host = host
|
35
|
+
end
|
36
|
+
|
37
|
+
def standalone standalone
|
38
|
+
self.standalone = standalone
|
39
|
+
end
|
40
|
+
|
41
|
+
def verify verify
|
42
|
+
self.verify = verify
|
43
|
+
end
|
44
|
+
|
45
|
+
def pact_specification_version pact_specification_version
|
46
|
+
self.pact_specification_version = pact_specification_version
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def finalize
|
51
|
+
raise 'Already finalized!' if @finalized
|
52
|
+
register_mock_service
|
53
|
+
configure_consumer_contract_builder
|
54
|
+
@finalized = true
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def register_mock_service
|
60
|
+
unless standalone
|
61
|
+
url = "http://#{host}#{port.nil? ? '' : ":#{port}"}"
|
62
|
+
ret = Pact::MockService::AppManager.instance.register_mock_service_for(provider_name, url, mock_service_options)
|
63
|
+
raise "pact-mock_service(v#{Pact::MockService::VERSION}) does not support 'find available port' feature" unless ret
|
64
|
+
@port = ret
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def configure_consumer_contract_builder
|
69
|
+
consumer_contract_builder = create_consumer_contract_builder
|
70
|
+
create_consumer_contract_builders_method consumer_contract_builder
|
71
|
+
setup_verification(consumer_contract_builder) if verify
|
72
|
+
consumer_contract_builder
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_consumer_contract_builder
|
76
|
+
consumer_contract_builder_fields = {
|
77
|
+
:consumer_name => consumer_name,
|
78
|
+
:provider_name => provider_name,
|
79
|
+
:pactfile_write_mode => Pact.configuration.pactfile_write_mode,
|
80
|
+
:port => port,
|
81
|
+
:host => host,
|
82
|
+
:pact_dir => Pact.configuration.pact_dir
|
83
|
+
}
|
84
|
+
Pact::Consumer::ConsumerContractBuilder.new consumer_contract_builder_fields
|
85
|
+
end
|
86
|
+
|
87
|
+
def setup_verification consumer_contract_builder
|
88
|
+
Pact.configuration.add_provider_verification do | example_description |
|
89
|
+
consumer_contract_builder.verify example_description
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# This makes the consumer_contract_builder available via a module method with the given identifier
|
94
|
+
# as the method name.
|
95
|
+
# I feel this should be defined somewhere else, but I'm not sure where
|
96
|
+
def create_consumer_contract_builders_method consumer_contract_builder
|
97
|
+
Pact::Consumer::ConsumerContractBuilders.send(:define_method, @name.to_sym) do
|
98
|
+
consumer_contract_builder
|
99
|
+
end
|
100
|
+
Pact.consumer_world.add_consumer_contract_builder consumer_contract_builder
|
101
|
+
end
|
102
|
+
|
103
|
+
def mock_service_options
|
104
|
+
{
|
105
|
+
pact_specification_version: pact_specification_version,
|
106
|
+
find_available_port: port.nil?,
|
107
|
+
}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'pact/shared/dsl'
|
2
|
+
|
3
|
+
module Pact
|
4
|
+
module Consumer
|
5
|
+
module Configuration
|
6
|
+
class ServiceConsumer
|
7
|
+
|
8
|
+
extend Pact::DSL
|
9
|
+
|
10
|
+
attr_accessor :app, :port, :name
|
11
|
+
|
12
|
+
def initialize name
|
13
|
+
@name = name
|
14
|
+
@app = nil
|
15
|
+
@port = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
dsl do
|
19
|
+
def app app
|
20
|
+
self.app = app
|
21
|
+
end
|
22
|
+
|
23
|
+
def port port
|
24
|
+
self.port = port
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_pact_with service_provider_name, &block
|
28
|
+
ServiceProvider.build(service_provider_name, name, &block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def finalize
|
33
|
+
validate
|
34
|
+
register_consumer_app if @app
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def validate
|
40
|
+
raise "Please provide a consumer name" unless (name && !name.empty?)
|
41
|
+
raise "Please provide a port for the consumer app" if app && !port
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def register_consumer_app
|
46
|
+
Pact::MockService::AppManager.instance.register app, port
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'pact/shared/dsl'
|
2
|
+
require 'pact/consumer/configuration/mock_service'
|
3
|
+
|
4
|
+
module Pact
|
5
|
+
module Consumer
|
6
|
+
module Configuration
|
7
|
+
class ServiceProvider
|
8
|
+
|
9
|
+
extend Pact::DSL
|
10
|
+
|
11
|
+
attr_accessor :service, :consumer_name, :name
|
12
|
+
|
13
|
+
def initialize name, consumer_name
|
14
|
+
@name = name
|
15
|
+
@service = nil
|
16
|
+
@consumer_name = consumer_name
|
17
|
+
end
|
18
|
+
|
19
|
+
dsl do
|
20
|
+
def mock_service name, &block
|
21
|
+
self.service = MockService.build(name, consumer_name, self.name, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def finalize
|
26
|
+
validate
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate
|
32
|
+
raise "Please configure a service for #{name}" unless service
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'pact/configuration'
|
2
|
+
require 'pact/consumer/consumer_contract_builders'
|
3
|
+
require 'pact/consumer/consumer_contract_builder'
|
4
|
+
require 'pact/consumer/configuration/service_consumer'
|
5
|
+
require 'pact/consumer/configuration/service_provider'
|
6
|
+
require 'pact/consumer/configuration/dsl'
|
7
|
+
require 'pact/consumer/configuration/configuration_extensions'
|
8
|
+
|
9
|
+
Pact.send(:extend, Pact::Consumer::DSL)
|
10
|
+
Pact::Configuration.send(:include, Pact::Consumer::Configuration::ConfigurationExtensions)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'json/add/regexp'
|
3
|
+
require 'pact/logging'
|
4
|
+
require 'pact/mock_service/client'
|
5
|
+
require 'pact/consumer/interaction_builder'
|
6
|
+
|
7
|
+
module Pact
|
8
|
+
module Consumer
|
9
|
+
|
10
|
+
class ConsumerContractBuilder
|
11
|
+
|
12
|
+
include Pact::Logging
|
13
|
+
|
14
|
+
attr_reader :mock_service_base_url
|
15
|
+
|
16
|
+
def initialize(attributes)
|
17
|
+
@interaction_builder = nil
|
18
|
+
@consumer_contract_details = {
|
19
|
+
consumer: {name: attributes[:consumer_name]},
|
20
|
+
provider: {name: attributes[:provider_name]},
|
21
|
+
pactfile_write_mode: attributes[:pactfile_write_mode].to_s,
|
22
|
+
pact_dir: attributes.fetch(:pact_dir)
|
23
|
+
}
|
24
|
+
@mock_service_client = Pact::MockService::Client.new(attributes[:port], attributes[:host])
|
25
|
+
@mock_service_base_url = "http://#{attributes[:host]}:#{attributes[:port]}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def without_writing_to_pact
|
29
|
+
interaction_builder.without_writing_to_pact
|
30
|
+
end
|
31
|
+
|
32
|
+
def given(provider_state)
|
33
|
+
interaction_builder.given(provider_state)
|
34
|
+
end
|
35
|
+
|
36
|
+
def upon_receiving(description)
|
37
|
+
interaction_builder.upon_receiving(description)
|
38
|
+
end
|
39
|
+
|
40
|
+
def verify example_description
|
41
|
+
mock_service_client.verify example_description
|
42
|
+
end
|
43
|
+
|
44
|
+
def log msg
|
45
|
+
mock_service_client.log msg
|
46
|
+
end
|
47
|
+
|
48
|
+
def write_pact
|
49
|
+
mock_service_client.write_pact @consumer_contract_details
|
50
|
+
end
|
51
|
+
|
52
|
+
def wait_for_interactions options = {}
|
53
|
+
wait_max_seconds = options.fetch(:wait_max_seconds, 3)
|
54
|
+
poll_interval = options.fetch(:poll_interval, 0.1)
|
55
|
+
mock_service_client.wait_for_interactions wait_max_seconds, poll_interval
|
56
|
+
end
|
57
|
+
|
58
|
+
# @raise Pact::InvalidInteractionError
|
59
|
+
def handle_interaction_fully_defined interaction
|
60
|
+
interaction.validate!
|
61
|
+
mock_service_client.add_expected_interaction interaction #TODO: What will happen if duplicate added?
|
62
|
+
self.interaction_builder = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
attr_reader :mock_service_client
|
68
|
+
attr_writer :interaction_builder
|
69
|
+
|
70
|
+
def interaction_builder
|
71
|
+
@interaction_builder ||=
|
72
|
+
begin
|
73
|
+
interaction_builder = InteractionBuilder.new do | interaction |
|
74
|
+
handle_interaction_fully_defined(interaction)
|
75
|
+
end
|
76
|
+
interaction_builder
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'pact/reification'
|
3
|
+
require 'pact/consumer_contract/interaction'
|
4
|
+
|
5
|
+
module Pact
|
6
|
+
module Consumer
|
7
|
+
class InteractionBuilder
|
8
|
+
|
9
|
+
attr_reader :interaction
|
10
|
+
|
11
|
+
def initialize &block
|
12
|
+
@interaction = Interaction.new
|
13
|
+
@callback = block
|
14
|
+
end
|
15
|
+
|
16
|
+
def without_writing_to_pact
|
17
|
+
interaction.metadata ||= {}
|
18
|
+
interaction.metadata[:write_to_pact] = false
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def upon_receiving description
|
23
|
+
@interaction.description = description
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def given provider_state
|
28
|
+
@interaction.provider_state = provider_state.nil? ? nil : provider_state.to_s
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def with(request_details)
|
33
|
+
interaction.request = Pact::Request::Expected.from_hash(request_details)
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def will_respond_with(response)
|
38
|
+
interaction.response = Pact::Response.new(response)
|
39
|
+
@callback.call interaction
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|