pact 1.1.0.rc1 → 1.1.0.rc2
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.
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +1 -1
- data/README.md +6 -2
- data/lib/pact/configuration.rb +4 -0
- data/lib/pact/consumer/consumer_contract_builder.rb +1 -1
- data/lib/pact/matchers/difference.rb +38 -0
- data/lib/pact/matchers/matchers.rb +1 -28
- data/lib/pact/matchers/nested_json_diff_decorator.rb +6 -1
- data/lib/pact/provider/pact_spec_runner.rb +28 -28
- data/lib/pact/provider/print_missing_provider_states.rb +2 -2
- data/lib/pact/provider/rspec/formatter.rb +63 -0
- data/lib/pact/provider/rspec/silent_json_formatter.rb +18 -0
- data/lib/pact/provider/rspec.rb +16 -7
- data/lib/pact/provider/world.rb +6 -0
- data/lib/pact/tasks/task_helper.rb +15 -18
- data/lib/pact/templates/provider_state.erb +0 -1
- data/lib/pact/version.rb +1 -1
- data/spec/lib/pact/matchers/difference_spec.rb +32 -0
- data/spec/lib/pact/tasks/task_helper_spec.rb +80 -0
- data/spec/lib/pact/verification_task_spec.rb +0 -10
- data/spec/support/pact_helper.rb +5 -2
- data/spec/support/stubbing.json +1 -1
- data/spec/support/term.json +36 -0
- data/spec/support/test_app_fail.json +29 -2
- data/spec/support/test_app_pass.json +4 -4
- data/tasks/pact-test.rake +12 -0
- metadata +11 -5
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@ Do this to generate your change history
|
|
|
2
2
|
|
|
3
3
|
git log --date=relative --pretty=format:' * %h - %s (%an, %ad)'
|
|
4
4
|
|
|
5
|
+
### 1.0.38 (24 March 2014)
|
|
6
|
+
|
|
7
|
+
* 7fb2bc3 - Improved readability of pact:verify specs by removing pactfile name and request details from output (bethesque, 23 hours ago)
|
|
8
|
+
* ff1de3c - Improving readability of error messages when pact:verify fails (bethesque, 23 hours ago)
|
|
9
|
+
* 8a08abf - Removed the last RSpec private API usage. I think. (bethesque, 33 hours ago)
|
|
10
|
+
* 6a0be58 - Reducing even more use of RSpec private APIs (bethesque, 33 hours ago)
|
|
11
|
+
* e1fd51c - Reducing use of RSpec private APIs (bethesque, 34 hours ago)
|
|
12
|
+
* 587cb90 - Replaced rspec 'commands to rerun failed examples' with Pact specific commands to rerun failed interactions (bethesque, 2 days ago)
|
|
13
|
+
|
|
5
14
|
### 1.0.37 (19 March 2014)
|
|
6
15
|
|
|
7
16
|
* 0e8b80e - Cleaned up pact:verify rspec matcher lines so the output makes more sense to the reader (bethesque, 3 minutes ago)
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -377,9 +377,13 @@ Configure the pact_uri in the Pact.service_provider block with the pact artifact
|
|
|
377
377
|
|
|
378
378
|
It should run with all your other tests. If an integration is broken, you want to know about it *before* you check in.
|
|
379
379
|
|
|
380
|
-
####
|
|
380
|
+
#### Stub calls to downstream systems
|
|
381
381
|
|
|
382
|
-
|
|
382
|
+
Consider making a separate pact with the downstream system and using shared fixtures.
|
|
383
|
+
|
|
384
|
+
#### Consider carefully whether to use the real database or stub calls
|
|
385
|
+
|
|
386
|
+
You may choose not stub your database calls for pact:verify. This can be a good time for you to test your database integration if you have a simple application, however, for a complex one, you might want to carefully choose a point at which to stub calls.
|
|
383
387
|
|
|
384
388
|
## Gotchas
|
|
385
389
|
|
data/lib/pact/configuration.rb
CHANGED
|
@@ -10,6 +10,8 @@ module Pact
|
|
|
10
10
|
attr_accessor :tmp_dir
|
|
11
11
|
attr_accessor :reports_dir
|
|
12
12
|
attr_writer :pactfile_write_mode
|
|
13
|
+
attr_accessor :error_stream
|
|
14
|
+
attr_accessor :output_stream
|
|
13
15
|
|
|
14
16
|
def log_path
|
|
15
17
|
log_dir + "/pact.log"
|
|
@@ -54,6 +56,8 @@ module Pact
|
|
|
54
56
|
c.logger = default_logger c.log_path
|
|
55
57
|
c.pactfile_write_mode = :overwrite
|
|
56
58
|
c.reports_dir = File.expand_path('./reports/pacts')
|
|
59
|
+
c.output_stream = $stdout
|
|
60
|
+
c.error_stream = $stderr
|
|
57
61
|
c
|
|
58
62
|
end
|
|
59
63
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Pact
|
|
2
|
+
module Matchers
|
|
3
|
+
class Difference
|
|
4
|
+
|
|
5
|
+
attr_reader :expected, :actual
|
|
6
|
+
|
|
7
|
+
def initialize expected, actual
|
|
8
|
+
@expected = expected
|
|
9
|
+
@actual = actual
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def any?
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_hash
|
|
17
|
+
if Regexp === expected
|
|
18
|
+
{:EXPECTED_TO_MATCH => expected.inspect, :ACTUAL => actual}
|
|
19
|
+
else
|
|
20
|
+
{:EXPECTED => expected, :ACTUAL => actual}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_json options = {}
|
|
25
|
+
to_hash.to_json(options)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_s
|
|
29
|
+
to_hash.to_s
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def == other
|
|
33
|
+
other.is_a?(Difference) && other.expected == expected && other.actual == actual
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -6,38 +6,11 @@ require 'pact/shared/key_not_found'
|
|
|
6
6
|
require 'pact/matchers/unexpected_key'
|
|
7
7
|
require 'pact/matchers/unexpected_index'
|
|
8
8
|
require 'pact/matchers/index_not_found'
|
|
9
|
+
require 'pact/matchers/difference'
|
|
9
10
|
|
|
10
11
|
module Pact
|
|
11
12
|
module Matchers
|
|
12
13
|
|
|
13
|
-
class Difference
|
|
14
|
-
attr_reader :expected, :actual
|
|
15
|
-
def initialize expected, actual
|
|
16
|
-
@expected = expected
|
|
17
|
-
@actual = actual
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def any?
|
|
21
|
-
true
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def to_hash
|
|
25
|
-
{:EXPECTED => expected, :ACTUAL => actual}
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def to_json options = {}
|
|
29
|
-
to_hash.to_json(options)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def to_s
|
|
33
|
-
to_hash.to_s
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def == other
|
|
37
|
-
other.is_a?(Difference) && other.expected == expected && other.actual == actual
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
14
|
class NoDiffIndicator
|
|
42
15
|
|
|
43
16
|
def to_json options = {}
|
|
@@ -9,6 +9,11 @@ module Pact
|
|
|
9
9
|
|
|
10
10
|
EXPECTED = '"EXPECTED"'
|
|
11
11
|
EXPECTED_COLOURED = '"' + "expected".red + '"'
|
|
12
|
+
|
|
13
|
+
EXPECTED_REGEXP = '"EXPECTED_TO_MATCH"'
|
|
14
|
+
EXPECTED_REGEXP_COLOURED = '"' + "expected_to_match".red + '"'
|
|
15
|
+
|
|
16
|
+
|
|
12
17
|
ACTUAL = '"ACTUAL"'
|
|
13
18
|
ACTUAL_COLOURED = '"' + "actual".green + '"'
|
|
14
19
|
|
|
@@ -39,7 +44,7 @@ module Pact
|
|
|
39
44
|
end
|
|
40
45
|
|
|
41
46
|
def colourise line
|
|
42
|
-
line.white.gsub(EXPECTED, EXPECTED_COLOURED).gsub(ACTUAL, ACTUAL_COLOURED)
|
|
47
|
+
line.white.gsub(EXPECTED, EXPECTED_COLOURED).gsub(ACTUAL, ACTUAL_COLOURED).gsub(EXPECTED_REGEXP, EXPECTED_REGEXP_COLOURED)
|
|
43
48
|
end
|
|
44
49
|
|
|
45
50
|
end
|
|
@@ -4,7 +4,8 @@ require 'rspec/core'
|
|
|
4
4
|
require 'rspec/core/formatters/documentation_formatter'
|
|
5
5
|
require 'rspec/core/formatters/json_formatter'
|
|
6
6
|
require 'pact/provider/pact_helper_locator'
|
|
7
|
-
require 'pact/provider/
|
|
7
|
+
require 'pact/provider/rspec/formatter'
|
|
8
|
+
require 'pact/provider/rspec/silent_json_formatter'
|
|
8
9
|
require_relative 'rspec'
|
|
9
10
|
|
|
10
11
|
|
|
@@ -36,6 +37,7 @@ module Pact
|
|
|
36
37
|
run_specs
|
|
37
38
|
ensure
|
|
38
39
|
::RSpec.reset
|
|
40
|
+
Pact.clear_world
|
|
39
41
|
end
|
|
40
42
|
end
|
|
41
43
|
|
|
@@ -43,11 +45,11 @@ module Pact
|
|
|
43
45
|
|
|
44
46
|
def require_pact_helper spec_definition
|
|
45
47
|
if spec_definition[:pact_helper]
|
|
46
|
-
puts "Using #{spec_definition[:pact_helper]}"
|
|
48
|
+
Pact.configuration.output_stream.puts "Using #{spec_definition[:pact_helper]}"
|
|
47
49
|
require spec_definition[:pact_helper]
|
|
48
50
|
elsif spec_definition[:support_file]
|
|
49
|
-
puts "Using #{spec_definition[:support_file]}"
|
|
50
|
-
|
|
51
|
+
Pact.configuration.output_stream.puts "Using #{spec_definition[:support_file]}"
|
|
52
|
+
Pact.configuration.error_stream.puts SUPPORT_FILE_DEPRECATION_MESSAGE
|
|
51
53
|
require spec_definition[:support_file]
|
|
52
54
|
else
|
|
53
55
|
require 'pact/provider/client_project_pact_helper'
|
|
@@ -70,42 +72,40 @@ module Pact
|
|
|
70
72
|
config = ::RSpec.configuration
|
|
71
73
|
|
|
72
74
|
config.color = true
|
|
75
|
+
config.pattern = "pattern which doesn't match any files"
|
|
76
|
+
config.backtrace_inclusion_patterns = [/pact\/provider\/rspec/]
|
|
77
|
+
config.backtrace_exclusion_patterns << /pact/
|
|
78
|
+
|
|
73
79
|
config.extend Pact::Provider::RSpec::ClassMethods
|
|
74
80
|
config.include Pact::Provider::RSpec::InstanceMethods
|
|
75
81
|
config.include Pact::Provider::TestMethods
|
|
76
|
-
config.backtrace_inclusion_patterns = [/pact\/provider\/rspec/]
|
|
77
82
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
if options[:silent]
|
|
84
|
+
config.output_stream = StringIO.new
|
|
85
|
+
config.error_stream = StringIO.new
|
|
86
|
+
else
|
|
87
|
+
config.error_stream = Pact.configuration.error_stream
|
|
88
|
+
config.output_stream = Pact.configuration.output_stream
|
|
81
89
|
end
|
|
82
90
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
config.output_stream = $stdout
|
|
86
|
-
end
|
|
91
|
+
config.add_formatter Pact::Provider::RSpec::Formatter
|
|
92
|
+
config.add_formatter Pact::Provider::RSpec::SilentJsonFormatter
|
|
87
93
|
|
|
88
|
-
formatter = ::RSpec::Core::Formatters::DocumentationFormatter.new(config.output)
|
|
89
|
-
@json_formatter = ::RSpec::Core::Formatters::JsonFormatter.new(StringIO.new)
|
|
90
|
-
reporter = ::RSpec::Core::Reporter.new(formatter, @json_formatter)
|
|
91
|
-
config.instance_variable_set(:@reporter, reporter)
|
|
92
94
|
end
|
|
93
95
|
|
|
94
96
|
def run_specs
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
begin
|
|
99
|
-
config.run_hook(:before, :suite)
|
|
100
|
-
world.example_groups.ordered.map {|g| g.run(reporter)}.all? ? 0 : config.failure_exit_code
|
|
101
|
-
ensure
|
|
102
|
-
config.run_hook(:after, :suite)
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
PrintMissingProviderStates.call Pact.world.provider_states.missing_provider_states
|
|
106
|
-
@output = @json_formatter.output_hash
|
|
97
|
+
exit_code = ::RSpec::Core::CommandLine.new(NoConfigurationOptions.new)
|
|
98
|
+
.run(::RSpec.configuration.output_stream, ::RSpec.configuration.error_stream)
|
|
99
|
+
@output = JSON.parse(Pact.world.json_formatter_stream.string, symbolize_keys: true)
|
|
107
100
|
exit_code
|
|
108
101
|
end
|
|
102
|
+
|
|
103
|
+
class NoConfigurationOptions
|
|
104
|
+
def method_missing(method, *args, &block)
|
|
105
|
+
# Do nothing!
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
109
|
end
|
|
110
110
|
end
|
|
111
111
|
end
|
|
@@ -3,9 +3,9 @@ module Pact
|
|
|
3
3
|
class PrintMissingProviderStates
|
|
4
4
|
|
|
5
5
|
# Hash of consumer names to array of names of missing provider states
|
|
6
|
-
def self.call missing_provider_states
|
|
6
|
+
def self.call missing_provider_states, output
|
|
7
7
|
if missing_provider_states.any?
|
|
8
|
-
puts orangeify(text(missing_provider_states))
|
|
8
|
+
output.puts orangeify(text(missing_provider_states))
|
|
9
9
|
end
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'pact/provider/print_missing_provider_states'
|
|
2
|
+
require 'rspec/core/formatters'
|
|
3
|
+
require 'colored'
|
|
4
|
+
|
|
5
|
+
module Pact
|
|
6
|
+
module Provider
|
|
7
|
+
module RSpec
|
|
8
|
+
class Formatter < ::RSpec::Core::Formatters::DocumentationFormatter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def dump_commands_to_rerun_failed_examples
|
|
12
|
+
return if failed_examples.empty?
|
|
13
|
+
|
|
14
|
+
print_rerun_commands
|
|
15
|
+
print_failure_message
|
|
16
|
+
print_missing_provider_states
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def print_rerun_commands
|
|
21
|
+
output.puts("\n")
|
|
22
|
+
interaction_failure_messages.each do | message |
|
|
23
|
+
output.puts(message)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def print_missing_provider_states
|
|
28
|
+
PrintMissingProviderStates.call Pact.world.provider_states.missing_provider_states, output
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def interaction_failure_messages
|
|
32
|
+
failed_examples.collect do |example|
|
|
33
|
+
interaction_failure_message_for example
|
|
34
|
+
end.uniq
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def interaction_failure_message_for example
|
|
38
|
+
provider_state = example.metadata[:pact_interaction].provider_state
|
|
39
|
+
description = example.metadata[:pact_interaction].description
|
|
40
|
+
pactfile_uri = example.metadata[:pactfile_uri]
|
|
41
|
+
example_description = example.metadata[:pact_interaction_example_description]
|
|
42
|
+
failure_color("rake pact:verify:at[#{pactfile_uri}] PACT_DESCRIPTION=\"#{description}\" PACT_PROVIDER_STATE=\"#{provider_state}\"") + " " + detail_color("# #{example_description}")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def print_failure_message
|
|
46
|
+
output.puts failure_message
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def failure_message
|
|
50
|
+
|
|
51
|
+
"\n" + "For assistance debugging failures, please note:".underline.yellow + "\n\n" +
|
|
52
|
+
"The pact files have been stored locally in the following temp directory:\n #{Pact.configuration.tmp_dir}\n\n" +
|
|
53
|
+
"The requests and responses are logged in the following log file:\n #{Pact.configuration.log_path}\n\n"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'rspec/core/formatters'
|
|
2
|
+
|
|
3
|
+
module Pact
|
|
4
|
+
module Provider
|
|
5
|
+
module RSpec
|
|
6
|
+
class SilentJsonFormatter < ::RSpec::Core::Formatters::JsonFormatter
|
|
7
|
+
|
|
8
|
+
def initialize stream
|
|
9
|
+
# Don't want to display this to the screen,
|
|
10
|
+
# not sure how else to set a custom stream for a particular formatter
|
|
11
|
+
# Store a reference to this so it can be inspected afterwards.
|
|
12
|
+
super(Pact.world.json_formatter_stream)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/pact/provider/rspec.rb
CHANGED
|
@@ -19,12 +19,10 @@ module Pact
|
|
|
19
19
|
include ::RSpec::Core::DSL
|
|
20
20
|
|
|
21
21
|
def honour_pactfile pactfile_uri, options = {}
|
|
22
|
-
puts "Filtering specs by: #{options[:criteria]}" if options[:criteria]
|
|
22
|
+
puts "Filtering specs by: #{options[:criteria]}" if options[:criteria] && options[:criteria].any?
|
|
23
23
|
consumer_contract = Pact::ConsumerContract.from_json(read_pact_from(pactfile_uri, options))
|
|
24
|
-
describe "
|
|
25
|
-
|
|
26
|
-
honour_consumer_contract consumer_contract, options
|
|
27
|
-
end
|
|
24
|
+
describe "Verifying a pact between #{consumer_contract.consumer.name} and #{consumer_contract.provider.name}", :pactfile_uri => pactfile_uri do
|
|
25
|
+
honour_consumer_contract consumer_contract, options
|
|
28
26
|
end
|
|
29
27
|
end
|
|
30
28
|
|
|
@@ -60,12 +58,19 @@ module Pact
|
|
|
60
58
|
|
|
61
59
|
def describe_interaction interaction, options
|
|
62
60
|
|
|
63
|
-
|
|
61
|
+
metadata = {
|
|
62
|
+
:pact => :verify,
|
|
63
|
+
:pact_interaction => interaction,
|
|
64
|
+
:pact_interaction_example_description => interaction_description_for_rerun_command(interaction)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
describe description_for(interaction), metadata do
|
|
64
68
|
|
|
65
69
|
interaction_context = InteractionContext.new
|
|
66
70
|
|
|
67
71
|
before do
|
|
68
72
|
interaction_context.run_once :before do
|
|
73
|
+
Pact.configuration.logger.info "Running example '#{self.example.full_description}'"
|
|
69
74
|
set_up_provider_state interaction.provider_state, options[:consumer]
|
|
70
75
|
replay_interaction interaction
|
|
71
76
|
interaction_context.last_response = last_response
|
|
@@ -119,7 +124,11 @@ module Pact
|
|
|
119
124
|
end
|
|
120
125
|
|
|
121
126
|
def description_for interaction
|
|
122
|
-
|
|
127
|
+
interaction.provider_state ? interaction.description : interaction.description.capitalize
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def interaction_description_for_rerun_command interaction
|
|
131
|
+
description_for(interaction).capitalize + ( interaction.provider_state ? " given #{interaction.provider_state}" : "")
|
|
123
132
|
end
|
|
124
133
|
|
|
125
134
|
def read_pact_from uri, options = {}
|
data/lib/pact/provider/world.rb
CHANGED
|
@@ -14,6 +14,12 @@ module Pact
|
|
|
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
|
+
|
|
17
23
|
def provider_states
|
|
18
24
|
@provider_states_proxy ||= Pact::Provider::State::ProviderStateProxy.new
|
|
19
25
|
end
|
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
module Pact
|
|
2
2
|
module TaskHelper
|
|
3
|
-
def failure_message
|
|
4
|
-
redify(
|
|
5
|
-
"\n* * * * * * * * * * * * * * * * * * *\n" +
|
|
6
|
-
"Provider did not honour pact file.\nSee\n * #{Pact.configuration.log_path}\n * #{Pact.configuration.tmp_dir}\nfor logs and pact files." +
|
|
7
|
-
"\n* * * * * * * * * * * * * * * * * * *\n\n"
|
|
8
|
-
)
|
|
9
|
-
end
|
|
10
3
|
|
|
11
|
-
|
|
12
|
-
"\e[31m#{string}\e[m"
|
|
13
|
-
end
|
|
4
|
+
extend self
|
|
14
5
|
|
|
15
6
|
def handle_verification_failure
|
|
16
7
|
exit_status = yield
|
|
17
|
-
if exit_status != 0
|
|
18
|
-
$stderr.puts failure_message
|
|
19
|
-
fail
|
|
20
|
-
end
|
|
8
|
+
abort if exit_status != 0
|
|
21
9
|
end
|
|
22
10
|
|
|
23
11
|
def spec_criteria defaults = {description: nil, provider_state: nil}
|
|
24
12
|
criteria = {}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
|
|
14
|
+
description = ENV.fetch("PACT_DESCRIPTION", defaults[:description])
|
|
15
|
+
criteria[:description] = Regexp.new(description) if description
|
|
16
|
+
|
|
17
|
+
provider_state = ENV.fetch("PACT_PROVIDER_STATE", defaults[:provider_state])
|
|
18
|
+
if provider_state
|
|
19
|
+
if provider_state.length == 0
|
|
20
|
+
criteria[:provider_state] = nil #Allow PACT_PROVIDER_STATE="" to mean no provider state
|
|
21
|
+
else
|
|
22
|
+
criteria[:provider_state] = Regexp.new(provider_state)
|
|
23
|
+
end
|
|
28
24
|
end
|
|
29
|
-
|
|
25
|
+
|
|
26
|
+
criteria
|
|
30
27
|
end
|
|
31
28
|
end
|
|
32
29
|
end
|
data/lib/pact/version.rb
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'pact/matchers/difference'
|
|
3
|
+
|
|
4
|
+
module Pact
|
|
5
|
+
module Matchers
|
|
6
|
+
describe Difference do
|
|
7
|
+
|
|
8
|
+
describe "#to_hash" do
|
|
9
|
+
|
|
10
|
+
context "when a regexp is expected" do
|
|
11
|
+
|
|
12
|
+
subject { Difference.new(/ap/, 'pear').to_hash }
|
|
13
|
+
|
|
14
|
+
it "indicates that the actual was indended 'to match'" do
|
|
15
|
+
expect(subject).to eq({:EXPECTED_TO_MATCH => "/ap/", :ACTUAL => "pear"})
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context "when something other than a regexp is expected" do
|
|
21
|
+
|
|
22
|
+
subject { Difference.new("apple", 'pear').to_hash }
|
|
23
|
+
|
|
24
|
+
it "indicates that the actual was intended 'to eq'" do
|
|
25
|
+
expect(subject).to eq({:EXPECTED => "apple", :ACTUAL => "pear"})
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'pact/tasks/task_helper'
|
|
3
|
+
|
|
4
|
+
module Pact
|
|
5
|
+
describe TaskHelper do
|
|
6
|
+
include TaskHelper
|
|
7
|
+
|
|
8
|
+
let(:env_description) { "pact description set in ENV"}
|
|
9
|
+
let(:env_provider_state) { "provider state set in ENV"}
|
|
10
|
+
let(:env_criteria){ {:description=>/#{env_description}/, :provider_state=>/#{env_provider_state}/} }
|
|
11
|
+
let(:default_description) { "default description"}
|
|
12
|
+
let(:default_provider_state) { "default provider state"}
|
|
13
|
+
|
|
14
|
+
shared_context "PACT_DESCRIPTION is defined" do
|
|
15
|
+
before do
|
|
16
|
+
ENV.stub(:[])
|
|
17
|
+
ENV.stub(:[]).with("PACT_DESCRIPTION").and_return(env_description)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
shared_context 'PACT_PROVIDER_STATE is defined' do
|
|
22
|
+
before do
|
|
23
|
+
ENV.stub(:[])
|
|
24
|
+
ENV.stub(:[]).with("PACT_PROVIDER_STATE").and_return(env_provider_state)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
shared_context 'default description is defined' do
|
|
29
|
+
let(:default_description) { "default description"}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
let(:defaults) { {:description => default_description, :provider_state => default_provider_state} }
|
|
33
|
+
|
|
34
|
+
describe "spec_criteria" do
|
|
35
|
+
|
|
36
|
+
context "when ENV variables are defined" do
|
|
37
|
+
before do
|
|
38
|
+
ENV.stub(:fetch).with("PACT_DESCRIPTION", anything).and_return(env_description)
|
|
39
|
+
ENV.stub(:fetch).with("PACT_PROVIDER_STATE", anything).and_return(env_provider_state)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
context "when defaults are not passed in" do
|
|
43
|
+
it "returns the env vars as regexes" do
|
|
44
|
+
expect(spec_criteria).to eq(env_criteria)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context "when defaults are passed in" do
|
|
49
|
+
it "returns the env vars as regexes" do
|
|
50
|
+
expect(spec_criteria(defaults)).to eq(env_criteria)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context "when ENV variables are not defined" do
|
|
56
|
+
context "when defaults are passed in" do
|
|
57
|
+
it "returns the defaults as regexes" do
|
|
58
|
+
expect(spec_criteria(defaults)).to eq({:description=>/#{default_description}/, :provider_state=>/#{default_provider_state}/})
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
context "when defaults are not passed in" do
|
|
62
|
+
it "returns an empty hash" do
|
|
63
|
+
expect(spec_criteria).to eq({})
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
context "when provider state is an empty string" do
|
|
69
|
+
before do
|
|
70
|
+
ENV.stub(:fetch).with(anything, anything).and_return(nil)
|
|
71
|
+
ENV.stub(:fetch).with("PACT_PROVIDER_STATE", anything).and_return('')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "returns a nil provider state so that it matches a nil provider state on the interaction" do
|
|
75
|
+
expect(spec_criteria[:provider_state]).to be_nil
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -88,16 +88,6 @@ module Pact
|
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
-
context 'when one or more specs fail' do
|
|
92
|
-
|
|
93
|
-
let(:exit_code) {1}
|
|
94
|
-
|
|
95
|
-
it 'raises an exception' do
|
|
96
|
-
$stderr.should_receive(:puts) #Confusing if this shows on the screen!
|
|
97
|
-
expect { Rake::Task[@task_name].execute }.to raise_error RuntimeError
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
end
|
|
101
91
|
end
|
|
102
92
|
end
|
|
103
93
|
end
|
data/spec/support/pact_helper.rb
CHANGED
|
@@ -28,12 +28,16 @@ module Pact
|
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
Pact.set_up do
|
|
32
|
+
WEATHER ||= {}
|
|
33
|
+
end
|
|
31
34
|
|
|
32
35
|
#one with a top level consumer
|
|
33
36
|
Pact.provider_states_for 'some-test-consumer' do
|
|
37
|
+
|
|
34
38
|
provider_state "the weather is sunny" do
|
|
35
39
|
set_up do
|
|
36
|
-
|
|
40
|
+
|
|
37
41
|
WEATHER[:current_state] = 'sunny'
|
|
38
42
|
end
|
|
39
43
|
end
|
|
@@ -42,7 +46,6 @@ module Pact
|
|
|
42
46
|
#one without a top level consumer
|
|
43
47
|
Pact.provider_state "the weather is cloudy" do
|
|
44
48
|
set_up do
|
|
45
|
-
WEATHER ||= {}
|
|
46
49
|
WEATHER[:current_state] = 'cloudy'
|
|
47
50
|
end
|
|
48
51
|
end
|
data/spec/support/stubbing.json
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"consumer": {
|
|
3
|
+
"name": "some-test-consumer"
|
|
4
|
+
},
|
|
5
|
+
"provider": {
|
|
6
|
+
"name": "an unknown provider"
|
|
7
|
+
},
|
|
8
|
+
"interactions": [
|
|
9
|
+
{
|
|
10
|
+
"description": "a test request",
|
|
11
|
+
"request": {
|
|
12
|
+
"method": "get",
|
|
13
|
+
"path": "/weather",
|
|
14
|
+
"query": ""
|
|
15
|
+
},
|
|
16
|
+
"response": {
|
|
17
|
+
"status": 200,
|
|
18
|
+
"headers" : {"Content-type": "application/json"},
|
|
19
|
+
"body": {
|
|
20
|
+
"message" : {
|
|
21
|
+
"json_class": "Pact::Term",
|
|
22
|
+
"data": {
|
|
23
|
+
"generate": "rainy",
|
|
24
|
+
"matcher": {
|
|
25
|
+
"json_class": "Regexp",
|
|
26
|
+
"o": 0,
|
|
27
|
+
"s": "rain"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"provider_state": "the weather is sunny"
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
},
|
|
5
5
|
"provider": {
|
|
6
6
|
"name": "an unknown provider"
|
|
7
|
-
},
|
|
7
|
+
},
|
|
8
8
|
"interactions": [
|
|
9
9
|
{
|
|
10
|
-
"description": "
|
|
10
|
+
"description": "a test request",
|
|
11
11
|
"request": {
|
|
12
12
|
"method": "get",
|
|
13
13
|
"path": "/weather",
|
|
@@ -20,6 +20,33 @@
|
|
|
20
20
|
|
|
21
21
|
},
|
|
22
22
|
"provider_state": "the weather is cloudy"
|
|
23
|
+
},{
|
|
24
|
+
"description": "another test request",
|
|
25
|
+
"request": {
|
|
26
|
+
"method": "get",
|
|
27
|
+
"path": "/weather",
|
|
28
|
+
"query": ""
|
|
29
|
+
},
|
|
30
|
+
"response": {
|
|
31
|
+
"status": 200,
|
|
32
|
+
"headers" : {"Content-type": "application/json"},
|
|
33
|
+
"body": {"message" : "this is not the weather you are looking for"}
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
},{
|
|
37
|
+
"description": "another test request",
|
|
38
|
+
"provider_state": "a missing provider state",
|
|
39
|
+
"request": {
|
|
40
|
+
"method": "get",
|
|
41
|
+
"path": "/weather",
|
|
42
|
+
"query": ""
|
|
43
|
+
},
|
|
44
|
+
"response": {
|
|
45
|
+
"status": 200,
|
|
46
|
+
"headers" : {"Content-type": "application/json"},
|
|
47
|
+
"body": {"message" : "this is not the weather you are looking for"}
|
|
48
|
+
|
|
49
|
+
}
|
|
23
50
|
}
|
|
24
51
|
]
|
|
25
52
|
}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
},
|
|
5
5
|
"provider": {
|
|
6
6
|
"name": "an unknown provider"
|
|
7
|
-
},
|
|
7
|
+
},
|
|
8
8
|
"interactions": [
|
|
9
9
|
{
|
|
10
|
-
"description": "
|
|
10
|
+
"description": "a test request",
|
|
11
11
|
"request": {
|
|
12
12
|
"method": "get",
|
|
13
13
|
"path": "/weather",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"provider_state": "the weather is sunny"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
|
-
"description": "
|
|
24
|
+
"description": "a test request for text",
|
|
25
25
|
"request": {
|
|
26
26
|
"method": "get",
|
|
27
27
|
"path": "/sometext",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"headers" : {"Content-type": "text/plain"},
|
|
34
34
|
"body": "some text"
|
|
35
35
|
}
|
|
36
|
-
}
|
|
36
|
+
}
|
|
37
37
|
]
|
|
38
38
|
}
|
data/tasks/pact-test.rake
CHANGED
|
@@ -8,6 +8,17 @@ Pact::VerificationTask.new(:stubbing_using_allow) do | pact |
|
|
|
8
8
|
pact.uri './spec/support/stubbing.json', :pact_helper => './spec/support/stubbing_using_allow.rb'
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
Pact::VerificationTask.new(:pass) do | pact |
|
|
12
|
+
pact.uri './spec/support/test_app_pass.json'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
Pact::VerificationTask.new(:fail) do | pact |
|
|
16
|
+
pact.uri './spec/support/test_app_fail.json'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Pact::VerificationTask.new(:term) do | pact |
|
|
20
|
+
pact.uri './spec/support/term.json'
|
|
21
|
+
end
|
|
11
22
|
|
|
12
23
|
namespace :pact do
|
|
13
24
|
|
|
@@ -20,6 +31,7 @@ namespace :pact do
|
|
|
20
31
|
silent = true
|
|
21
32
|
puts "Running task pact:tests"
|
|
22
33
|
# Run these specs silently, otherwise expected failures will be written to stdout and look like unexpected failures.
|
|
34
|
+
Pact.configuration.output_stream = StringIO.new if silent
|
|
23
35
|
|
|
24
36
|
result = Pact::Provider::PactSpecRunner.new([{ uri: './spec/support/test_app_pass.json' }], silent: silent).run
|
|
25
37
|
fail 'Expected pact to pass' unless (result == 0)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pact
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.0.
|
|
4
|
+
version: 1.1.0.rc2
|
|
5
5
|
prerelease: 6
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -13,7 +13,7 @@ authors:
|
|
|
13
13
|
autorequire:
|
|
14
14
|
bindir: bin
|
|
15
15
|
cert_chain: []
|
|
16
|
-
date: 2014-03-
|
|
16
|
+
date: 2014-03-24 00:00:00.000000000 Z
|
|
17
17
|
dependencies:
|
|
18
18
|
- !ruby/object:Gem::Dependency
|
|
19
19
|
name: randexp
|
|
@@ -362,6 +362,7 @@ files:
|
|
|
362
362
|
- lib/pact/logging.rb
|
|
363
363
|
- lib/pact/matchers.rb
|
|
364
364
|
- lib/pact/matchers/diff_decorator.rb
|
|
365
|
+
- lib/pact/matchers/difference.rb
|
|
365
366
|
- lib/pact/matchers/index_not_found.rb
|
|
366
367
|
- lib/pact/matchers/matchers.rb
|
|
367
368
|
- lib/pact/matchers/nested_json_diff_decorator.rb
|
|
@@ -378,6 +379,8 @@ files:
|
|
|
378
379
|
- lib/pact/provider/print_missing_provider_states.rb
|
|
379
380
|
- lib/pact/provider/request.rb
|
|
380
381
|
- lib/pact/provider/rspec.rb
|
|
382
|
+
- lib/pact/provider/rspec/formatter.rb
|
|
383
|
+
- lib/pact/provider/rspec/silent_json_formatter.rb
|
|
381
384
|
- lib/pact/provider/state/provider_state.rb
|
|
382
385
|
- lib/pact/provider/state/provider_state_configured_modules.rb
|
|
383
386
|
- lib/pact/provider/state/provider_state_manager.rb
|
|
@@ -426,6 +429,7 @@ files:
|
|
|
426
429
|
- spec/lib/pact/consumer_contract/interaction_spec.rb
|
|
427
430
|
- spec/lib/pact/consumer_contract/request_spec.rb
|
|
428
431
|
- spec/lib/pact/matchers/diff_decorator_spec.rb
|
|
432
|
+
- spec/lib/pact/matchers/difference_spec.rb
|
|
429
433
|
- spec/lib/pact/matchers/matchers_spec.rb
|
|
430
434
|
- spec/lib/pact/matchers/nested_json_diff_decorator_spec.rb
|
|
431
435
|
- spec/lib/pact/matchers/plus_minus_diff_decorator_spec.rb
|
|
@@ -442,6 +446,7 @@ files:
|
|
|
442
446
|
- spec/lib/pact/reification_spec.rb
|
|
443
447
|
- spec/lib/pact/shared/dsl_spec.rb
|
|
444
448
|
- spec/lib/pact/something_like_spec.rb
|
|
449
|
+
- spec/lib/pact/tasks/task_helper_spec.rb
|
|
445
450
|
- spec/lib/pact/term_spec.rb
|
|
446
451
|
- spec/lib/pact/verification_task_spec.rb
|
|
447
452
|
- spec/spec_helper.rb
|
|
@@ -457,6 +462,7 @@ files:
|
|
|
457
462
|
- spec/support/stubbing.json
|
|
458
463
|
- spec/support/stubbing.rb
|
|
459
464
|
- spec/support/stubbing_using_allow.rb
|
|
465
|
+
- spec/support/term.json
|
|
460
466
|
- spec/support/test_app_fail.json
|
|
461
467
|
- spec/support/test_app_pass.json
|
|
462
468
|
- tasks/pact-test.rake
|
|
@@ -474,9 +480,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
474
480
|
- - ! '>='
|
|
475
481
|
- !ruby/object:Gem::Version
|
|
476
482
|
version: '0'
|
|
477
|
-
segments:
|
|
478
|
-
- 0
|
|
479
|
-
hash: -3201059694268013519
|
|
480
483
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
481
484
|
none: false
|
|
482
485
|
requirements:
|
|
@@ -517,6 +520,7 @@ test_files:
|
|
|
517
520
|
- spec/lib/pact/consumer_contract/interaction_spec.rb
|
|
518
521
|
- spec/lib/pact/consumer_contract/request_spec.rb
|
|
519
522
|
- spec/lib/pact/matchers/diff_decorator_spec.rb
|
|
523
|
+
- spec/lib/pact/matchers/difference_spec.rb
|
|
520
524
|
- spec/lib/pact/matchers/matchers_spec.rb
|
|
521
525
|
- spec/lib/pact/matchers/nested_json_diff_decorator_spec.rb
|
|
522
526
|
- spec/lib/pact/matchers/plus_minus_diff_decorator_spec.rb
|
|
@@ -533,6 +537,7 @@ test_files:
|
|
|
533
537
|
- spec/lib/pact/reification_spec.rb
|
|
534
538
|
- spec/lib/pact/shared/dsl_spec.rb
|
|
535
539
|
- spec/lib/pact/something_like_spec.rb
|
|
540
|
+
- spec/lib/pact/tasks/task_helper_spec.rb
|
|
536
541
|
- spec/lib/pact/term_spec.rb
|
|
537
542
|
- spec/lib/pact/verification_task_spec.rb
|
|
538
543
|
- spec/spec_helper.rb
|
|
@@ -548,5 +553,6 @@ test_files:
|
|
|
548
553
|
- spec/support/stubbing.json
|
|
549
554
|
- spec/support/stubbing.rb
|
|
550
555
|
- spec/support/stubbing_using_allow.rb
|
|
556
|
+
- spec/support/term.json
|
|
551
557
|
- spec/support/test_app_fail.json
|
|
552
558
|
- spec/support/test_app_pass.json
|