pact 1.1.1 → 1.2.1.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +42 -39
- data/README.md +2 -0
- data/documentation/configuration.md +2 -2
- data/documentation/faq.md +5 -7
- data/documentation/provider-states.md +2 -10
- data/example/animal-service/spec/service_consumers/pact_helper.rb +0 -4
- data/lib/pact/consumer/configuration/mock_service.rb +2 -0
- data/lib/pact/consumer/consumer_contract_builder.rb +58 -58
- data/lib/pact/consumer/mock_service/app.rb +4 -1
- data/lib/pact/consumer/mock_service/interaction_replay.rb +11 -3
- data/lib/pact/consumer/mock_service/missing_interactions_get.rb +2 -2
- data/lib/pact/consumer/mock_service/pact_post.rb +33 -0
- data/lib/pact/consumer/mock_service/verification_get.rb +1 -2
- data/lib/pact/consumer/mock_service_client.rb +14 -5
- data/lib/pact/consumer/mock_service_interaction_expectation.rb +1 -1
- data/lib/pact/consumer/spec_hooks.rb +2 -0
- data/lib/pact/consumer/world.rb +25 -0
- data/lib/pact/consumer_contract/consumer_contract.rb +1 -1
- data/lib/pact/consumer_contract/consumer_contract_writer.rb +84 -0
- data/lib/pact/consumer_contract/file_name.rb +7 -1
- data/lib/pact/provider/pact_helper_locator.rb +1 -1
- data/lib/pact/provider/pact_spec_runner.rb +3 -9
- data/lib/pact/provider/rspec/{formatter.rb → formatter_rspec_2.rb} +2 -2
- data/lib/pact/provider/rspec/formatter_rspec_3.rb +96 -0
- data/lib/pact/provider/rspec/matchers.rb +79 -19
- data/lib/pact/provider/rspec.rb +3 -1
- data/lib/pact/provider/state/provider_state_configured_modules.rb +6 -0
- data/lib/pact/provider/state/provider_state_manager.rb +3 -3
- data/lib/pact/provider/world.rb +2 -8
- data/lib/pact/rspec.rb +32 -0
- data/lib/pact/version.rb +1 -1
- data/pact.gemspec +3 -3
- data/spec/features/consumption_spec.rb +6 -1
- data/spec/integration/consumer_spec.rb +16 -9
- data/spec/integration/pact/consumer_configuration_spec.rb +7 -22
- data/spec/lib/pact/app_spec.rb +5 -5
- data/spec/lib/pact/configuration_spec.rb +1 -1
- data/spec/lib/pact/consumer/app_manager_spec.rb +3 -3
- data/spec/lib/pact/consumer/configuration_spec.rb +11 -8
- data/spec/lib/pact/consumer/consumer_contract_builder_spec.rb +3 -101
- data/spec/lib/pact/consumer/interaction_builder_spec.rb +8 -8
- data/spec/lib/pact/consumer/mock_service/app_spec.rb +2 -2
- data/spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb +2 -2
- data/spec/lib/pact/consumer/mock_service/interaction_replay_spec.rb +12 -0
- data/spec/lib/pact/consumer/mock_service/verification_get_spec.rb +2 -2
- data/spec/lib/pact/consumer/mock_service_client_spec.rb +88 -0
- data/spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb +4 -4
- data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +18 -18
- data/spec/lib/pact/consumer_contract/consumer_contract_writer_spec.rb +111 -0
- data/spec/lib/pact/provider/configuration/pact_verification_spec.rb +1 -1
- data/spec/lib/pact/provider/pact_helper_locator_spec.rb +2 -2
- data/spec/lib/pact/provider/rspec/{formatter_spec.rb → formatter_rspec_2_spec.rb} +14 -4
- data/spec/lib/pact/provider/rspec/formatter_rspec_3_spec.rb +72 -0
- data/spec/lib/pact/provider/rspec_spec.rb +3 -0
- data/spec/lib/pact/provider/state/provider_state_manager_spec.rb +1 -1
- data/spec/lib/pact/provider/state/provider_state_proxy_spec.rb +4 -4
- data/spec/lib/pact/provider/state/provider_state_spec.rb +7 -7
- data/spec/lib/pact/provider/world_spec.rb +8 -8
- data/spec/lib/pact/tasks/verification_task_spec.rb +2 -2
- data/spec/spec_helper.rb +2 -4
- data/spec/support/factories.rb +13 -13
- data/spec/support/spec_support.rb +10 -0
- data/spec/support/stubbing_using_allow.rb +0 -4
- data/tasks/pact-test.rake +12 -8
- metadata +27 -24
- data/bethtest.rb +0 -30
- data/lib/pact/provider/rspec/silent_json_formatter.rb +0 -18
- data/spec/support/stubbing.rb +0 -26
@@ -102,7 +102,7 @@ module Pact
|
|
102
102
|
|
103
103
|
def pactfile_path
|
104
104
|
raise 'You must first specify a consumer and service name' unless (consumer && consumer.name && provider && provider.name)
|
105
|
-
@pactfile_path ||=
|
105
|
+
@pactfile_path ||= file_path consumer.name, provider.name
|
106
106
|
end
|
107
107
|
|
108
108
|
def update_pactfile
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'pact/consumer_contract'
|
2
|
+
require 'pact/consumer/interactions_filter'
|
3
|
+
require 'pact/consumer_contract/file_name'
|
4
|
+
|
5
|
+
module Pact
|
6
|
+
|
7
|
+
class ConsumerContractWriter
|
8
|
+
|
9
|
+
attr_reader :consumer_contract_details, :pactfile_write_mode, :interactions, :logger
|
10
|
+
|
11
|
+
def initialize consumer_contract_details, logger
|
12
|
+
@logger = logger
|
13
|
+
@consumer_contract_details = consumer_contract_details
|
14
|
+
@pactfile_write_mode = consumer_contract_details.fetch(:pactfile_write_mode, :overwrite).to_sym
|
15
|
+
@interactions = consumer_contract_details.fetch(:interactions)
|
16
|
+
end
|
17
|
+
|
18
|
+
def consumer_contract
|
19
|
+
@consumer_contract ||= Pact::ConsumerContract.new(
|
20
|
+
consumer: ServiceConsumer.new(name: consumer_contract_details[:consumer][:name]),
|
21
|
+
provider: ServiceProvider.new(name: consumer_contract_details[:provider][:name]),
|
22
|
+
interactions: interactions_for_new_consumer_contract)
|
23
|
+
end
|
24
|
+
|
25
|
+
def write
|
26
|
+
consumer_contract.update_pactfile
|
27
|
+
consumer_contract.to_json
|
28
|
+
end
|
29
|
+
|
30
|
+
def interactions_for_new_consumer_contract
|
31
|
+
if pactfile_write_mode == :update
|
32
|
+
merged_interactions = existing_interactions
|
33
|
+
filter = Consumer::UpdatableInteractionsFilter.new(merged_interactions)
|
34
|
+
interactions.each {|i| filter << i }
|
35
|
+
merged_interactions
|
36
|
+
else
|
37
|
+
interactions
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def existing_interactions
|
42
|
+
interactions = []
|
43
|
+
if pactfile_exists?
|
44
|
+
begin
|
45
|
+
interactions = existing_consumer_contract.interactions
|
46
|
+
info_and_puts "*****************************************************************************"
|
47
|
+
info_and_puts "Updating existing file .#{pactfile_path.gsub(Dir.pwd, '')} as config.pactfile_write_mode is :update"
|
48
|
+
info_and_puts "Only interactions defined in this test run will be updated."
|
49
|
+
info_and_puts "As interactions are identified by description and provider state, pleased note that if either of these have changed, the old interactions won't be removed from the pact file until the specs are next run with :pactfile_write_mode => :overwrite."
|
50
|
+
info_and_puts "*****************************************************************************"
|
51
|
+
rescue StandardError => e
|
52
|
+
warn_and_stderr "Could not load existing consumer contract from #{pactfile_path} due to #{e}"
|
53
|
+
logger.error e
|
54
|
+
logger.error e.backtrace
|
55
|
+
warn_and_stderr "Creating a new file."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
interactions
|
59
|
+
end
|
60
|
+
|
61
|
+
def pactfile_exists?
|
62
|
+
File.exist?(pactfile_path)
|
63
|
+
end
|
64
|
+
|
65
|
+
def pactfile_path
|
66
|
+
Pact::FileName.file_path consumer_contract_details[:consumer][:name], consumer_contract_details[:provider][:name]
|
67
|
+
end
|
68
|
+
|
69
|
+
def existing_consumer_contract
|
70
|
+
Pact::ConsumerContract.from_uri(pactfile_path)
|
71
|
+
end
|
72
|
+
|
73
|
+
def warn_and_stderr msg
|
74
|
+
Pact.configuration.error_stream.puts msg
|
75
|
+
logger.warn msg
|
76
|
+
end
|
77
|
+
|
78
|
+
def info_and_puts msg
|
79
|
+
$stdout.puts msg
|
80
|
+
logger.info msg
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -1,11 +1,17 @@
|
|
1
1
|
module Pact
|
2
2
|
|
3
|
-
#TODO move to external file for reuse
|
4
3
|
module FileName
|
4
|
+
|
5
|
+
extend self
|
6
|
+
|
5
7
|
def file_name consumer_name, provider_name
|
6
8
|
"#{filenamify(consumer_name)}-#{filenamify(provider_name)}.json"
|
7
9
|
end
|
8
10
|
|
11
|
+
def file_path consumer_name, provider_name, pact_dir = Pact.configuration.pact_dir
|
12
|
+
File.join(pact_dir, file_name(consumer_name, provider_name))
|
13
|
+
end
|
14
|
+
|
9
15
|
def filenamify name
|
10
16
|
name.downcase.gsub(/\s/, '_')
|
11
17
|
end
|
@@ -13,7 +13,7 @@ module Pact
|
|
13
13
|
pact_helper_search_results = []
|
14
14
|
PACT_HELPER_FILE_PATTERNS.find { | pattern | (pact_helper_search_results.concat(Dir.glob(pattern))).any? }
|
15
15
|
raise NO_PACT_HELPER_FOUND_MSG if pact_helper_search_results.empty?
|
16
|
-
|
16
|
+
File.join(Dir.pwd, pact_helper_search_results[0])
|
17
17
|
end
|
18
18
|
|
19
19
|
end
|
@@ -2,10 +2,7 @@ require 'open-uri'
|
|
2
2
|
require 'rspec'
|
3
3
|
require 'rspec/core'
|
4
4
|
require 'rspec/core/formatters/documentation_formatter'
|
5
|
-
require 'rspec/core/formatters/json_formatter'
|
6
5
|
require 'pact/provider/pact_helper_locator'
|
7
|
-
require 'pact/provider/rspec/formatter'
|
8
|
-
require 'pact/provider/rspec/silent_json_formatter'
|
9
6
|
require 'pact/project_root'
|
10
7
|
require 'pact/rspec'
|
11
8
|
|
@@ -35,7 +32,7 @@ module Pact
|
|
35
32
|
run_specs
|
36
33
|
ensure
|
37
34
|
::RSpec.reset
|
38
|
-
Pact.
|
35
|
+
Pact.clear_provider_world
|
39
36
|
end
|
40
37
|
end
|
41
38
|
|
@@ -72,8 +69,7 @@ module Pact
|
|
72
69
|
config.output_stream = Pact.configuration.output_stream
|
73
70
|
end
|
74
71
|
|
75
|
-
config.add_formatter Pact::
|
76
|
-
config.add_formatter Pact::Provider::RSpec::SilentJsonFormatter
|
72
|
+
config.add_formatter Pact::RSpec.formatter_class
|
77
73
|
|
78
74
|
config.before(:suite) do
|
79
75
|
# Preload app before suite so the classes loaded in memory are consistent for
|
@@ -87,13 +83,11 @@ module Pact
|
|
87
83
|
|
88
84
|
def run_specs
|
89
85
|
exit_code = if Pact::RSpec.runner_defined?
|
90
|
-
::RSpec::Core::Runner.run(rspec_runner_options
|
91
|
-
::RSpec.configuration.output_stream, ::RSpec.configuration.error_stream)
|
86
|
+
::RSpec::Core::Runner.run(rspec_runner_options)
|
92
87
|
else
|
93
88
|
::RSpec::Core::CommandLine.new(NoConfigurationOptions.new)
|
94
89
|
.run(::RSpec.configuration.output_stream, ::RSpec.configuration.error_stream)
|
95
90
|
end
|
96
|
-
@output = JSON.parse(Pact.world.json_formatter_stream.string, symbolize_keys: true)
|
97
91
|
exit_code
|
98
92
|
end
|
99
93
|
|
@@ -5,7 +5,7 @@ require 'term/ansicolor'
|
|
5
5
|
module Pact
|
6
6
|
module Provider
|
7
7
|
module RSpec
|
8
|
-
class
|
8
|
+
class Formatter2 < ::RSpec::Core::Formatters::DocumentationFormatter
|
9
9
|
|
10
10
|
C = ::Term::ANSIColor
|
11
11
|
|
@@ -28,7 +28,7 @@ module Pact
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def print_missing_provider_states
|
31
|
-
PrintMissingProviderStates.call Pact.
|
31
|
+
PrintMissingProviderStates.call Pact.provider_world.provider_states.missing_provider_states, output
|
32
32
|
end
|
33
33
|
|
34
34
|
def interaction_rerun_commands
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'pact/provider/print_missing_provider_states'
|
2
|
+
require 'rspec/core/formatters'
|
3
|
+
require 'term/ansicolor'
|
4
|
+
|
5
|
+
module Pact
|
6
|
+
module Provider
|
7
|
+
module RSpec
|
8
|
+
class Formatter < ::RSpec::Core::Formatters::DocumentationFormatter
|
9
|
+
|
10
|
+
Pact::RSpec.with_rspec_3 do
|
11
|
+
::RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished,
|
12
|
+
:example_passed, :example_pending, :example_failed
|
13
|
+
end
|
14
|
+
|
15
|
+
C = ::Term::ANSIColor
|
16
|
+
|
17
|
+
def dump_summary(summary)
|
18
|
+
output.puts "\n" + colorized_totals_line(summary)
|
19
|
+
return if summary.failure_count == 0
|
20
|
+
print_rerun_commands summary
|
21
|
+
print_failure_message
|
22
|
+
print_missing_provider_states
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def interactions_count(summary)
|
28
|
+
summary.examples.collect{ |e|e.metadata[:pact_interaction_example_description]}.uniq.size
|
29
|
+
end
|
30
|
+
|
31
|
+
def failed_interactions_count(summary)
|
32
|
+
summary.failed_examples.collect{ |e|e.metadata[:pact_interaction_example_description]}.uniq.size
|
33
|
+
end
|
34
|
+
|
35
|
+
def totals_line summary
|
36
|
+
line = ::RSpec::Core::Formatters::Helpers.pluralize(interactions_count(summary), "interaction")
|
37
|
+
line << ", " << ::RSpec::Core::Formatters::Helpers.pluralize(failed_interactions_count(summary), "failure")
|
38
|
+
line
|
39
|
+
end
|
40
|
+
|
41
|
+
def colorized_totals_line(summary)
|
42
|
+
if summary.failure_count > 0
|
43
|
+
colorizer.wrap(totals_line(summary), ::RSpec.configuration.failure_color)
|
44
|
+
else
|
45
|
+
colorizer.wrap(totals_line(summary), ::RSpec.configuration.success_color)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def print_rerun_commands summary
|
50
|
+
output.puts("\nFailed interactions:\n\n")
|
51
|
+
interaction_rerun_commands(summary).each do | message |
|
52
|
+
output.puts(message)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def print_missing_provider_states
|
57
|
+
PrintMissingProviderStates.call Pact.provider_world.provider_states.missing_provider_states, output
|
58
|
+
end
|
59
|
+
|
60
|
+
def interaction_rerun_commands summary
|
61
|
+
summary.failed_examples.collect do |example|
|
62
|
+
interaction_rerun_command_for example
|
63
|
+
end.uniq
|
64
|
+
end
|
65
|
+
|
66
|
+
def interaction_rerun_command_for example
|
67
|
+
provider_state = example.metadata[:pact_interaction].provider_state
|
68
|
+
description = example.metadata[:pact_interaction].description
|
69
|
+
pactfile_uri = example.metadata[:pactfile_uri]
|
70
|
+
example_description = example.metadata[:pact_interaction_example_description]
|
71
|
+
colorizer.wrap("rake pact:verify:at[#{pactfile_uri}] PACT_DESCRIPTION=\"#{description}\" PACT_PROVIDER_STATE=\"#{provider_state}\" ", ::RSpec.configuration.failure_color) +
|
72
|
+
colorizer.wrap("# #{example_description}", ::RSpec.configuration.detail_color)
|
73
|
+
end
|
74
|
+
|
75
|
+
def print_failure_message
|
76
|
+
output.puts failure_message
|
77
|
+
end
|
78
|
+
|
79
|
+
def failure_message
|
80
|
+
"\n" + C.underline(C.yellow("For assistance debugging failures, please note:")) + "\n\n" +
|
81
|
+
"The pact files have been stored locally in the following temp directory:\n #{Pact.configuration.tmp_dir}\n\n" +
|
82
|
+
"The requests and responses are logged in the following log file:\n #{Pact.configuration.log_path}\n\n"
|
83
|
+
end
|
84
|
+
|
85
|
+
def colorizer
|
86
|
+
@colorizer ||= ::RSpec::Core::Formatters::ConsoleCodes
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
|
@@ -3,32 +3,92 @@ require 'pact/matchers'
|
|
3
3
|
require 'pact/provider/matchers/messages'
|
4
4
|
require 'pact/rspec'
|
5
5
|
|
6
|
-
|
6
|
+
module Pact
|
7
|
+
module RSpec
|
8
|
+
module Matchers
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
+
module RSpec2Delegator
|
11
|
+
# For backwards compatiblity with rspec-2
|
12
|
+
def method_missing(method, *args, &block)
|
13
|
+
if method_name == :failure_message_for_should
|
14
|
+
failure_message method, *args, &block
|
15
|
+
else
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
10
20
|
|
11
|
-
|
12
|
-
(@difference = diff(expected, actual)).empty?
|
13
|
-
end
|
21
|
+
class MatchTerm
|
14
22
|
|
15
|
-
|
16
|
-
|
17
|
-
|
23
|
+
include Pact::Matchers
|
24
|
+
include Pact::Matchers::Messages
|
25
|
+
include RSpec2Delegator
|
18
26
|
|
19
|
-
|
27
|
+
def initialize expected
|
28
|
+
@expected = expected
|
29
|
+
end
|
20
30
|
|
21
|
-
|
31
|
+
def matches? actual
|
32
|
+
@actual = actual
|
33
|
+
(@difference = diff(@expected, @actual)).empty?
|
34
|
+
end
|
22
35
|
|
23
|
-
|
24
|
-
|
36
|
+
def failure_message
|
37
|
+
match_term_failure_message @difference, @actual, Pact::RSpec.color_enabled?
|
38
|
+
end
|
25
39
|
|
26
|
-
|
27
|
-
|
28
|
-
|
40
|
+
end
|
41
|
+
|
42
|
+
def match_term expected
|
43
|
+
MatchTerm.new(expected)
|
44
|
+
end
|
45
|
+
|
46
|
+
class MatchHeader
|
47
|
+
|
48
|
+
include Pact::Matchers
|
49
|
+
include Pact::Matchers::Messages
|
50
|
+
include RSpec2Delegator
|
51
|
+
|
52
|
+
def initialize header_name, expected
|
53
|
+
@header_name = header_name
|
54
|
+
@expected = expected
|
55
|
+
end
|
56
|
+
|
57
|
+
def matches? actual
|
58
|
+
@actual = actual
|
59
|
+
diff(@expected, @actual).empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def failure_message
|
63
|
+
match_header_failure_message @header_name, @expected, @actual
|
64
|
+
end
|
29
65
|
|
30
|
-
|
31
|
-
|
66
|
+
end
|
67
|
+
|
68
|
+
def match_header header_name, expected
|
69
|
+
MatchHeader.new(header_name, expected)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
32
73
|
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# RSpec::Matchers.define :match_header do |header_name, expected|
|
78
|
+
|
79
|
+
# include Pact::Matchers
|
80
|
+
# include Pact::Matchers::Messages
|
81
|
+
|
82
|
+
# match do |actual|
|
83
|
+
# diff(expected, actual).empty?
|
84
|
+
# end
|
85
|
+
|
86
|
+
# def failure_message_for_should(actual)
|
87
|
+
# match_header_failure_message header_name, expected, actual
|
88
|
+
# end
|
89
|
+
|
90
|
+
# # failure_message_for_should do | actual |
|
91
|
+
# # match_header_failure_message header_name, expected, actual
|
92
|
+
# # end
|
33
93
|
|
34
|
-
end
|
94
|
+
# end
|
data/lib/pact/provider/rspec.rb
CHANGED
@@ -23,7 +23,7 @@ module Pact
|
|
23
23
|
puts "Reading pact at #{pactfile_uri}"
|
24
24
|
puts "Filtering interactions by: #{options[:criteria]}" if options[:criteria] && options[:criteria].any?
|
25
25
|
consumer_contract = Pact::ConsumerContract.from_json(read_pact_from(pactfile_uri, options))
|
26
|
-
describe "Verifying a pact between #{consumer_contract.consumer.name} and #{consumer_contract.provider.name}", :pactfile_uri => pactfile_uri do
|
26
|
+
::RSpec.describe "Verifying a pact between #{consumer_contract.consumer.name} and #{consumer_contract.provider.name}", :pactfile_uri => pactfile_uri do
|
27
27
|
honour_consumer_contract consumer_contract, options
|
28
28
|
end
|
29
29
|
end
|
@@ -99,6 +99,8 @@ module Pact
|
|
99
99
|
|
100
100
|
describe "returns a response which" do
|
101
101
|
|
102
|
+
include Pact::RSpec::Matchers
|
103
|
+
|
102
104
|
let(:expected_response_status) { expected_response['status'] }
|
103
105
|
let(:expected_response_body) { expected_response['body'] }
|
104
106
|
let(:response) { interaction_context.last_response }
|
@@ -26,15 +26,15 @@ module Pact
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def get_provider_state
|
29
|
-
Pact.
|
29
|
+
Pact.provider_world.provider_states.get(provider_state_name, :for => consumer)
|
30
30
|
end
|
31
31
|
|
32
32
|
def get_consumer_base_provider_state
|
33
|
-
Pact.
|
33
|
+
Pact.provider_world.provider_states.get_base(:for => consumer)
|
34
34
|
end
|
35
35
|
|
36
36
|
def get_global_base_provider_state
|
37
|
-
Pact.
|
37
|
+
Pact.provider_world.provider_states.get_base
|
38
38
|
end
|
39
39
|
|
40
40
|
end
|
data/lib/pact/provider/world.rb
CHANGED
@@ -2,24 +2,18 @@ require 'pact/provider/state/provider_state_proxy'
|
|
2
2
|
|
3
3
|
module Pact
|
4
4
|
|
5
|
-
def self.
|
5
|
+
def self.provider_world
|
6
6
|
@world ||= Pact::Provider::World.new
|
7
7
|
end
|
8
8
|
|
9
9
|
# internal api, for testing only
|
10
|
-
def self.
|
10
|
+
def self.clear_provider_world
|
11
11
|
@world = nil
|
12
12
|
end
|
13
13
|
|
14
14
|
module Provider
|
15
15
|
class World
|
16
16
|
|
17
|
-
attr_reader :json_formatter_stream
|
18
|
-
|
19
|
-
def initialize
|
20
|
-
@json_formatter_stream = StringIO.new
|
21
|
-
end
|
22
|
-
|
23
17
|
def provider_states
|
24
18
|
@provider_states_proxy ||= Pact::Provider::State::ProviderStateProxy.new
|
25
19
|
end
|
data/lib/pact/rspec.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# This is horrible, must work out a better way of doing this
|
1
2
|
module Pact
|
2
3
|
module RSpec
|
3
4
|
|
@@ -9,6 +10,17 @@ module Pact
|
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
13
|
+
def self.formatter_class
|
14
|
+
if ::RSpec::Core::Formatters.respond_to?(:register)
|
15
|
+
require 'pact/provider/rspec/formatter_rspec_3'
|
16
|
+
Pact::Provider::RSpec::Formatter
|
17
|
+
else
|
18
|
+
require 'pact/provider/rspec/formatter_rspec_2'
|
19
|
+
Pact::Provider::RSpec::Formatter2
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
12
24
|
def self.full_description example
|
13
25
|
example.respond_to?(:full_description) ? example.full_description : example.example.full_description
|
14
26
|
end
|
@@ -16,5 +28,25 @@ module Pact
|
|
16
28
|
def self.runner_defined?
|
17
29
|
defined?(::RSpec::Core::Runner)
|
18
30
|
end
|
31
|
+
|
32
|
+
def self.is_rspec_3
|
33
|
+
::RSpec::Core::Formatters.respond_to?(:register)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.is_rspec_2
|
37
|
+
!is_rspec_3
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.with_rspec_3
|
41
|
+
if is_rspec_3
|
42
|
+
yield
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.with_rspec_2
|
47
|
+
if is_rspec_2
|
48
|
+
yield
|
49
|
+
end
|
50
|
+
end
|
19
51
|
end
|
20
52
|
end
|
data/lib/pact/version.rb
CHANGED
data/pact.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.license = 'MIT'
|
20
20
|
|
21
21
|
gem.add_runtime_dependency 'randexp', '~> 0.1.7'
|
22
|
-
gem.add_runtime_dependency 'rspec', '
|
22
|
+
gem.add_runtime_dependency 'rspec', '>=2.14'
|
23
23
|
gem.add_runtime_dependency 'find_a_port', '~> 1.0.1'
|
24
24
|
gem.add_runtime_dependency 'rack-test', '~> 0.6.2'
|
25
25
|
gem.add_runtime_dependency 'awesome_print', '~> 1.1'
|
@@ -29,10 +29,10 @@ Gem::Specification.new do |gem|
|
|
29
29
|
gem.add_runtime_dependency 'term-ansicolor', '~> 1.0'
|
30
30
|
|
31
31
|
gem.add_development_dependency 'rake', '~> 10.0.3'
|
32
|
-
gem.add_development_dependency 'webmock', '~> 1.
|
32
|
+
gem.add_development_dependency 'webmock', '~> 1.18.0'
|
33
33
|
gem.add_development_dependency 'pry'
|
34
34
|
gem.add_development_dependency 'fakefs', '~> 0.4'
|
35
35
|
gem.add_development_dependency 'hashie', '~> 2.0'
|
36
|
-
gem.add_development_dependency 'rspec-fire'
|
37
36
|
gem.add_development_dependency 'activesupport'
|
37
|
+
gem.add_development_dependency 'faraday'
|
38
38
|
end
|
@@ -1,14 +1,19 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
require 'pact/consumer'
|
3
3
|
require 'pact/consumer/rspec'
|
4
|
+
load 'pact/consumer/world.rb'
|
4
5
|
|
5
6
|
describe "A service consumer side of a pact", :pact => true do
|
6
7
|
|
8
|
+
before do
|
9
|
+
Pact.clear_configuration
|
10
|
+
Pact.clear_consumer_world
|
11
|
+
end
|
12
|
+
|
7
13
|
describe "blah" do
|
8
14
|
describe "thing" do
|
9
15
|
|
10
16
|
it "goes a little something like this" do
|
11
|
-
Pact.clear_configuration
|
12
17
|
|
13
18
|
Pact.service_consumer "Consumer" do
|
14
19
|
has_pact_with "Alice Service" do
|
@@ -2,6 +2,8 @@ require 'spec_helper'
|
|
2
2
|
require 'net/http'
|
3
3
|
require 'pact/consumer'
|
4
4
|
require 'pact/consumer/rspec'
|
5
|
+
require 'faraday'
|
6
|
+
load 'pact/consumer/world.rb'
|
5
7
|
|
6
8
|
describe "A service consumer side of a pact", :pact => true do
|
7
9
|
|
@@ -12,6 +14,7 @@ describe "A service consumer side of a pact", :pact => true do
|
|
12
14
|
|
13
15
|
it "returns an error" do
|
14
16
|
Pact.clear_configuration
|
17
|
+
Pact.clear_consumer_world
|
15
18
|
|
16
19
|
Pact.service_consumer "Consumer" do
|
17
20
|
has_pact_with "Mary Service" do
|
@@ -109,6 +112,8 @@ describe "A service consumer side of a pact", :pact => true do
|
|
109
112
|
end
|
110
113
|
end
|
111
114
|
|
115
|
+
let(:body) { 'That is some good Mallory.' }
|
116
|
+
|
112
117
|
it "goes like this" do
|
113
118
|
zebra_service.
|
114
119
|
given(:the_zebras_are_here).
|
@@ -120,12 +125,14 @@ describe "A service consumer side of a pact", :pact => true do
|
|
120
125
|
will_respond_with({
|
121
126
|
status: 200,
|
122
127
|
headers: { 'Content-Type' => 'text/html' },
|
123
|
-
body: Pact::Term.new(matcher: /Mallory/, generate:
|
128
|
+
body: Pact::Term.new(matcher: /Mallory/, generate: body)
|
124
129
|
})
|
125
130
|
|
126
|
-
|
127
|
-
|
128
|
-
|
131
|
+
response = Faraday.get(zebra_service.mock_service_base_url + "/mallory", nil, {'Accept' => 'text/html'})
|
132
|
+
expect(response.body).to eq body
|
133
|
+
|
134
|
+
interactions = Pact::ConsumerContract.from_json(zebra_service.write_pact).interactions
|
135
|
+
expect(interactions.first.provider_state).to eq("the_zebras_are_here")
|
129
136
|
end
|
130
137
|
end
|
131
138
|
|
@@ -146,11 +153,6 @@ describe "A service consumer side of a pact", :pact => true do
|
|
146
153
|
upon_receiving("a request with multiple headers").
|
147
154
|
with(method: :get, path: '/something', headers: {'X-Something' => "1, 2"}).
|
148
155
|
will_respond_with(status: 200)
|
149
|
-
end
|
150
|
-
|
151
|
-
it "handles multiple headers with the same name in a comma separated list" do
|
152
|
-
interactions = Pact::ConsumerContract.from_json(File.read(multi_headers_service.consumer_contract.pactfile_path)).interactions
|
153
|
-
expect(interactions.first.request.headers['X-Something']).to eq("1, 2")
|
154
156
|
|
155
157
|
uri = URI('http://localhost:1240/something')
|
156
158
|
post_req = Net::HTTP::Get.new(uri.path)
|
@@ -161,6 +163,11 @@ describe "A service consumer side of a pact", :pact => true do
|
|
161
163
|
end
|
162
164
|
end
|
163
165
|
|
166
|
+
it "handles multiple headers with the same name in a comma separated list" do
|
167
|
+
interactions = Pact::ConsumerContract.from_json(multi_headers_service.write_pact).interactions
|
168
|
+
expect(interactions.first.request.headers['X-Something']).to eq("1, 2")
|
169
|
+
end
|
170
|
+
|
164
171
|
end
|
165
172
|
|
166
173
|
context "with a async interaction with provider" do
|