pact 1.0.4 → 1.0.5
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 +5 -0
- data/Gemfile.lock +1 -1
- data/lib/pact/consumer_contract/consumer_contract.rb +35 -20
- data/lib/pact/pact_task_helper.rb +9 -3
- data/lib/pact/provider/pact_spec_runner.rb +25 -11
- data/lib/pact/provider/rspec.rb +2 -0
- data/lib/pact/provider/verification_report.rb +32 -0
- data/lib/pact/verification_task.rb +29 -2
- data/lib/pact/version.rb +1 -1
- data/spec/lib/pact/provider/pact_spec_runner_spec.rb +1 -1
- data/spec/lib/pact/verification_task_spec.rb +11 -10
- data/tasks/pact-test.rake +2 -2
- metadata +2 -1
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
### 1.0.5 (6 September 2013)
|
2
|
+
|
3
|
+
* Added verification reports when running rake pact:verify:xxx [Latheesh Padukana, Beth Skurrie]
|
4
|
+
* Changed pact:verify failure message to display in red [Latheesh Padukana, Beth Skurrie]
|
5
|
+
|
1
6
|
### 1.0.4 (6 September 2013)
|
2
7
|
|
3
8
|
* Added pact/tasks as an easy way to load the rake tasks and classes into the client project [Beth Skurrie]
|
data/Gemfile.lock
CHANGED
@@ -3,15 +3,31 @@ require 'pact/logging'
|
|
3
3
|
require 'pact/json_warning'
|
4
4
|
require 'date'
|
5
5
|
require 'pact/version'
|
6
|
+
require 'open-uri'
|
6
7
|
require_relative 'service_consumer'
|
7
8
|
require_relative 'service_provider'
|
8
9
|
require_relative 'interaction'
|
9
10
|
|
11
|
+
|
12
|
+
|
10
13
|
module Pact
|
14
|
+
|
15
|
+
#TODO move to external file for reuse
|
16
|
+
module FileName
|
17
|
+
def file_name consumer_name, provider_name
|
18
|
+
"#{filenamify(consumer_name)}-#{filenamify(provider_name)}.json"
|
19
|
+
end
|
20
|
+
|
21
|
+
def filenamify name
|
22
|
+
name.downcase.gsub(/\s/, '_')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
11
26
|
class ConsumerContract
|
12
27
|
|
13
|
-
include
|
14
|
-
include
|
28
|
+
include Logging
|
29
|
+
include JsonWarning
|
30
|
+
include FileName
|
15
31
|
|
16
32
|
attr_accessor :interactions
|
17
33
|
attr_accessor :consumer
|
@@ -37,7 +53,8 @@ module Pact
|
|
37
53
|
end
|
38
54
|
|
39
55
|
def to_json(options = {})
|
40
|
-
as_json(options).to_json(
|
56
|
+
as_json(options).to_json(
|
57
|
+
)
|
41
58
|
end
|
42
59
|
|
43
60
|
def self.from_hash(obj)
|
@@ -53,6 +70,10 @@ module Pact
|
|
53
70
|
from_hash(deserialised_object)
|
54
71
|
end
|
55
72
|
|
73
|
+
def self.from_uri uri
|
74
|
+
from_json(open(uri){ |f| f.read })
|
75
|
+
end
|
76
|
+
|
56
77
|
def self.maintain_backwards_compatiblity_with_producer_keys string
|
57
78
|
string.gsub('"producer":', '"provider":').gsub('"producer_state":', '"provider_state":')
|
58
79
|
end
|
@@ -78,26 +99,20 @@ module Pact
|
|
78
99
|
end
|
79
100
|
|
80
101
|
def pact_file_name
|
81
|
-
|
102
|
+
file_name consumer.name, provider.name
|
82
103
|
end
|
83
104
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
def update_pactfile
|
90
|
-
logger.debug "Updating pact file for #{provider.name} at #{pactfile_path}"
|
91
|
-
check_for_active_support_json
|
92
|
-
File.open(pactfile_path, 'w') do |f|
|
93
|
-
f.write JSON.pretty_generate(self)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
private
|
105
|
+
def pactfile_path
|
106
|
+
raise 'You must first specify a consumer and service name' unless (consumer && consumer.name && provider && provider.name)
|
107
|
+
@pactfile_path ||= File.join(Pact.configuration.pact_dir, pact_file_name)
|
108
|
+
end
|
98
109
|
|
99
|
-
|
100
|
-
|
110
|
+
def update_pactfile
|
111
|
+
logger.debug "Updating pact file for #{provider.name} at #{pactfile_path}"
|
112
|
+
check_for_active_support_json
|
113
|
+
File.open(pactfile_path, 'w') do |f|
|
114
|
+
f.write JSON.pretty_generate(self)
|
101
115
|
end
|
116
|
+
end
|
102
117
|
end
|
103
118
|
end
|
@@ -1,7 +1,13 @@
|
|
1
1
|
module PactTaskHelper
|
2
2
|
def failure_message
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
redify(
|
4
|
+
"\n* * * * * * * * * * * * * * * * * * *\n" +
|
5
|
+
"Provider did not honour pact file.\nSee\n * #{Pact.configuration.log_path}\n * #{Pact.configuration.tmp_dir}\nfor logs and pact files." +
|
6
|
+
"\n* * * * * * * * * * * * * * * * * * *\n\n"
|
7
|
+
)
|
8
|
+
end
|
9
|
+
|
10
|
+
def redify string
|
11
|
+
"\e[31m#{string}\e[m"
|
6
12
|
end
|
7
13
|
end
|
@@ -2,6 +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'
|
5
6
|
require_relative 'rspec'
|
6
7
|
|
7
8
|
|
@@ -9,7 +10,11 @@ module Pact
|
|
9
10
|
module Provider
|
10
11
|
class PactSpecRunner
|
11
12
|
|
12
|
-
|
13
|
+
include Pact::Provider::RSpec::ClassMethods
|
14
|
+
|
15
|
+
attr_reader :spec_definitions
|
16
|
+
attr_reader :options
|
17
|
+
attr_reader :output
|
13
18
|
|
14
19
|
PACT_HELPER_FILE_PATTERNS = [
|
15
20
|
"spec/**/*service*consumer*/pact_helper.rb",
|
@@ -19,15 +24,21 @@ module Pact
|
|
19
24
|
|
20
25
|
NO_PACT_HELPER_FOUND_MSG = "Please create a pact_helper.rb file that can be found using one of the following patterns: #{PACT_HELPER_FILE_PATTERNS.join(", ")}"
|
21
26
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
27
|
+
def initialize spec_definitions, options = {}
|
28
|
+
@spec_definitions = spec_definitions
|
29
|
+
@options = options
|
30
|
+
@results = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def run
|
34
|
+
initialize_specs
|
35
|
+
configure_rspec
|
25
36
|
run_specs
|
26
37
|
end
|
27
38
|
|
28
39
|
private
|
29
40
|
|
30
|
-
def
|
41
|
+
def require_pact_helper spec_definition
|
31
42
|
if spec_definition[:support_file]
|
32
43
|
require spec_definition[:support_file]
|
33
44
|
else
|
@@ -35,14 +46,14 @@ module Pact
|
|
35
46
|
end
|
36
47
|
end
|
37
48
|
|
38
|
-
def
|
49
|
+
def pact_helper_file
|
39
50
|
pact_helper_search_results = []
|
40
51
|
PACT_HELPER_FILE_PATTERNS.find { | pattern | (pact_helper_search_results.concat(Dir.glob(pattern))).any? }
|
41
52
|
raise NO_PACT_HELPER_FOUND_MSG if pact_helper_search_results.empty?
|
42
53
|
"#{Dir.pwd}/#{pact_helper_search_results[0]}"
|
43
54
|
end
|
44
55
|
|
45
|
-
def
|
56
|
+
def initialize_specs
|
46
57
|
spec_definitions.each do | spec_definition |
|
47
58
|
require_pact_helper spec_definition
|
48
59
|
options = {consumer: spec_definition[:consumer], save_pactfile_to_tmp: true}
|
@@ -50,7 +61,7 @@ module Pact
|
|
50
61
|
end
|
51
62
|
end
|
52
63
|
|
53
|
-
def
|
64
|
+
def configure_rspec
|
54
65
|
config = ::RSpec.configuration
|
55
66
|
config.color = true
|
56
67
|
|
@@ -60,14 +71,15 @@ module Pact
|
|
60
71
|
end
|
61
72
|
|
62
73
|
formatter = ::RSpec::Core::Formatters::DocumentationFormatter.new(config.output)
|
63
|
-
|
74
|
+
@json_formatter = ::RSpec::Core::Formatters::JsonFormatter.new(StringIO.new)
|
75
|
+
reporter = ::RSpec::Core::Reporter.new(formatter, @json_formatter)
|
64
76
|
config.instance_variable_set(:@reporter, reporter)
|
65
77
|
end
|
66
78
|
|
67
|
-
def
|
79
|
+
def run_specs
|
68
80
|
config = ::RSpec.configuration
|
69
81
|
world = ::RSpec::world
|
70
|
-
config.reporter.report(world.example_count, nil) do |reporter|
|
82
|
+
exit_code = config.reporter.report(world.example_count, nil) do |reporter|
|
71
83
|
begin
|
72
84
|
config.run_hook(:before, :suite)
|
73
85
|
world.example_groups.ordered.map {|g| g.run(reporter)}.all? ? 0 : config.failure_exit_code
|
@@ -75,6 +87,8 @@ module Pact
|
|
75
87
|
config.run_hook(:after, :suite)
|
76
88
|
end
|
77
89
|
end
|
90
|
+
@output = @json_formatter.output_hash
|
91
|
+
exit_code
|
78
92
|
end
|
79
93
|
end
|
80
94
|
end
|
data/lib/pact/provider/rspec.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'pact/consumer_contract'
|
2
|
+
|
3
|
+
module Pact::Provider
|
4
|
+
class VerificationReport
|
5
|
+
|
6
|
+
include Pact::FileName
|
7
|
+
|
8
|
+
def initialize (options)
|
9
|
+
@consumer = options[:consumer]
|
10
|
+
@provider = options[:provider]
|
11
|
+
@result = options[:result]
|
12
|
+
@output = options[:output]
|
13
|
+
end
|
14
|
+
|
15
|
+
def as_json
|
16
|
+
{
|
17
|
+
:consumer => @consumer,
|
18
|
+
:provider => @provider,
|
19
|
+
:result => @result,
|
20
|
+
:output => @output
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_json(options = {})
|
25
|
+
as_json.to_json(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def report_file_name
|
29
|
+
file_name("#{@consumer[:name]}_#{@consumer[:ref]}", "#{@provider[:name]}_#{@provider[:ref]}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rake/tasklib'
|
2
2
|
require 'pact/provider/pact_spec_runner'
|
3
3
|
require_relative 'pact_task_helper'
|
4
|
+
require_relative 'provider/verification_report'
|
4
5
|
|
5
6
|
=begin
|
6
7
|
To create a rake pact:verify:<something> task
|
@@ -48,12 +49,38 @@ module Pact
|
|
48
49
|
|
49
50
|
attr_reader :name
|
50
51
|
|
52
|
+
def parse_pactfile config
|
53
|
+
Pact::ConsumerContract.from_uri config[:uri]
|
54
|
+
end
|
55
|
+
|
56
|
+
def publish_report config, output, result
|
57
|
+
consumer_contract = parse_pactfile config
|
58
|
+
#TODO - when checking out a historical version, provider ref will be prod, however it will think it is head. Fix this!!!!
|
59
|
+
report = Provider::VerificationReport.new(
|
60
|
+
:result => result,
|
61
|
+
:output => output,
|
62
|
+
:consumer => {:name => consumer_contract.consumer.name, :ref => name},
|
63
|
+
:provider => {:name => consumer_contract.provider.name, :ref => 'head'}
|
64
|
+
)
|
65
|
+
|
66
|
+
FileUtils.mkdir_p "./reports/pact"
|
67
|
+
File.open("./reports/pact/#{report.report_file_name}", "w") { |file| file << JSON.pretty_generate(report) }
|
68
|
+
end
|
69
|
+
|
51
70
|
def define_rake_task
|
52
71
|
namespace :pact do
|
53
72
|
desc "Verify provider against the consumer pacts for #{name}"
|
54
73
|
task "verify:#{name}" do
|
55
|
-
|
56
|
-
|
74
|
+
|
75
|
+
exit_statuses = pact_spec_config.collect do | config |
|
76
|
+
#TODO: Change this to accept the ConsumerContract that is already parsed, so we don't make the same request twice
|
77
|
+
pact_spec_runner = Provider::PactSpecRunner.new([config])
|
78
|
+
exit_status = pact_spec_runner.run
|
79
|
+
publish_report config, pact_spec_runner.output, exit_status == 0
|
80
|
+
exit_status
|
81
|
+
end
|
82
|
+
|
83
|
+
fail failure_message if exit_statuses.any?{ | status | status != 0 }
|
57
84
|
end
|
58
85
|
end
|
59
86
|
end
|
data/lib/pact/version.rb
CHANGED
@@ -5,7 +5,7 @@ module Pact::Provider
|
|
5
5
|
describe PactSpecRunner do
|
6
6
|
describe "pact_helper_file", :fakefs => true do
|
7
7
|
|
8
|
-
subject { PactSpecRunner.send(:pact_helper_file) }
|
8
|
+
subject { PactSpecRunner.new({}).send(:pact_helper_file) }
|
9
9
|
|
10
10
|
def make_pactfile dir
|
11
11
|
FileUtils.mkdir_p ".#{dir}"
|
@@ -19,6 +19,16 @@ module Pact
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
before do
|
23
|
+
VerificationTask.any_instance.stub(:publish_report)
|
24
|
+
Provider::PactSpecRunner.stub(:new).with(consumer_contract).and_return(pact_spec_runner)
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:pact_spec_runner) { double('PactSpecRunner', :run => exit_code, :output => nil)}
|
28
|
+
let(:exit_code) {0}
|
29
|
+
let(:consumer_contract) { [ uri: @pact_uri, support_file: nil ] }
|
30
|
+
|
31
|
+
|
22
32
|
describe '.initialize' do
|
23
33
|
context 'with an explict support_file' do
|
24
34
|
it 'creates the tasks' do
|
@@ -34,11 +44,9 @@ module Pact
|
|
34
44
|
|
35
45
|
describe 'execute' do
|
36
46
|
|
37
|
-
let(:consumer_contract) { [ uri: @pact_uri, support_file: nil ] }
|
38
47
|
|
39
48
|
context "with no explict support file " do
|
40
49
|
it 'verifies the pacts using PactSpecRunner' do
|
41
|
-
Provider::PactSpecRunner.should_receive(:run).with(consumer_contract).and_return(0)
|
42
50
|
Rake::Task[@task_name].execute
|
43
51
|
end
|
44
52
|
end
|
@@ -46,17 +54,12 @@ module Pact
|
|
46
54
|
context "with an explict support_file" do
|
47
55
|
let(:consumer_contract) { [ uri: @pact_uri, support_file: @support_file] }
|
48
56
|
it 'verifies the pacts using PactSpecRunner' do
|
49
|
-
Provider::PactSpecRunner.should_receive(:run).with(consumer_contract).and_return(0)
|
50
57
|
Rake::Task[@task_name_with_explict_support_file].execute
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
54
61
|
context 'when all specs pass' do
|
55
62
|
|
56
|
-
before do
|
57
|
-
Provider::PactSpecRunner.stub(:run).and_return(0)
|
58
|
-
end
|
59
|
-
|
60
63
|
it 'does not raise an exception' do
|
61
64
|
Rake::Task[@task_name].execute
|
62
65
|
end
|
@@ -64,9 +67,7 @@ module Pact
|
|
64
67
|
|
65
68
|
context 'when one or more specs fail' do
|
66
69
|
|
67
|
-
|
68
|
-
Provider::PactSpecRunner.stub(:run).and_return(1)
|
69
|
-
end
|
70
|
+
let(:exit_code) {1}
|
70
71
|
|
71
72
|
it 'raises an exception' do
|
72
73
|
expect { Rake::Task[@task_name].execute }.to raise_error RuntimeError
|
data/tasks/pact-test.rake
CHANGED
@@ -8,10 +8,10 @@ namespace :pact do
|
|
8
8
|
puts "Running task pact:tests"
|
9
9
|
# Run these specs silently, otherwise expected failures will be written to stdout and look like unexpected failures.
|
10
10
|
|
11
|
-
result = Pact::Provider::PactSpecRunner.
|
11
|
+
result = Pact::Provider::PactSpecRunner.new([{ uri: './spec/support/test_app_pass.json' }], silent: silent).run
|
12
12
|
fail 'Expected pact to pass' unless (result == 0)
|
13
13
|
|
14
|
-
result = Pact::Provider::PactSpecRunner.
|
14
|
+
result = Pact::Provider::PactSpecRunner.new([{ uri: './spec/support/test_app_fail.json', support_file: './spec/support/pact_helper.rb' }], silent: silent).run
|
15
15
|
fail 'Expected pact to fail' if (result == 0)
|
16
16
|
|
17
17
|
puts "Task pact:tests completed succesfully."
|
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.0.
|
4
|
+
version: 1.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -299,6 +299,7 @@ files:
|
|
299
299
|
- lib/pact/provider/provider_state.rb
|
300
300
|
- lib/pact/provider/rspec.rb
|
301
301
|
- lib/pact/provider/test_methods.rb
|
302
|
+
- lib/pact/provider/verification_report.rb
|
302
303
|
- lib/pact/reification.rb
|
303
304
|
- lib/pact/request.rb
|
304
305
|
- lib/pact/tasks.rb
|