pact 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/CHANGELOG.md +31 -20
  2. data/Gemfile.lock +12 -12
  3. data/README.md +32 -16
  4. data/Rakefile +3 -3
  5. data/documentation/README.md +1 -0
  6. data/documentation/development-workflow.md +22 -0
  7. data/documentation/faq.md +8 -0
  8. data/documentation/provider-states.md +2 -0
  9. data/documentation/troubleshooting.md +4 -0
  10. data/documentation/verifying-pacts.md +97 -0
  11. data/lib/pact/app.rb +98 -4
  12. data/lib/pact/consumer/rspec.rb +3 -2
  13. data/lib/pact/doc/doc_file.rb +4 -4
  14. data/lib/pact/doc/generator.rb +3 -3
  15. data/lib/pact/doc/interaction_view_model.rb +1 -0
  16. data/lib/pact/doc/markdown/{interactions_renderer.rb → consumer_contract_renderer.rb} +1 -1
  17. data/lib/pact/doc/markdown/generator.rb +2 -2
  18. data/lib/pact/matchers/unix_diff_formatter.rb +1 -1
  19. data/lib/pact/project_root.rb +7 -0
  20. data/lib/pact/provider.rb +0 -1
  21. data/lib/pact/provider/context.rb +0 -0
  22. data/lib/pact/provider/matchers/messages.rb +15 -13
  23. data/lib/pact/provider/pact_spec_runner.rb +21 -22
  24. data/lib/pact/provider/rspec.rb +22 -15
  25. data/lib/pact/provider/rspec/custom_options_file +0 -0
  26. data/lib/pact/provider/{matchers.rb → rspec/matchers.rb} +2 -1
  27. data/lib/pact/rspec.rb +20 -0
  28. data/lib/pact/shared/request.rb +1 -1
  29. data/lib/pact/tasks/task_helper.rb +18 -15
  30. data/lib/pact/tasks/verification_task.rb +26 -32
  31. data/lib/pact/version.rb +1 -1
  32. data/lib/tasks/pact.rake +5 -11
  33. data/spec/integration/pact/consumer_configuration_spec.rb +3 -3
  34. data/spec/lib/pact/app_spec.rb +47 -0
  35. data/spec/lib/pact/consumer/app_manager_spec.rb +1 -1
  36. data/spec/lib/pact/consumer/mock_service/interaction_list_spec.rb +3 -3
  37. data/spec/lib/pact/consumer/mock_service/verification_get_spec.rb +10 -2
  38. data/spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb +2 -2
  39. data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +1 -1
  40. data/spec/lib/pact/consumer_contract/interaction_spec.rb +4 -4
  41. data/spec/lib/pact/consumer_contract/request_spec.rb +23 -23
  42. data/spec/lib/pact/doc/generator_spec.rb +4 -4
  43. data/spec/lib/pact/doc/markdown/{interactions_renderer_spec.rb → consumer_contract_renderer_spec.rb} +4 -4
  44. data/spec/lib/pact/matchers/unix_diff_formatter_spec.rb +8 -8
  45. data/spec/lib/pact/provider/configuration/configuration_extension_spec.rb +2 -2
  46. data/spec/lib/pact/provider/matchers/messages_spec.rb +17 -6
  47. data/spec/lib/pact/provider/rspec/formatter_spec.rb +3 -1
  48. data/spec/lib/pact/shared/dsl_spec.rb +1 -1
  49. data/spec/lib/pact/shared/request_spec.rb +8 -0
  50. data/spec/lib/pact/tasks/task_helper_spec.rb +39 -54
  51. data/spec/lib/pact/tasks/verification_task_spec.rb +75 -0
  52. data/spec/pact_specification/compliance-1.0.0.rb +47 -0
  53. data/spec/spec_helper.rb +2 -6
  54. data/spec/standalone/consumer_fail_test.rb +1 -0
  55. data/spec/standalone/consumer_pass_test.rb +1 -0
  56. data/spec/support/active_support_if_configured.rb +6 -0
  57. data/spec/support/pact_helper.rb +2 -1
  58. data/spec/support/shared_examples_for_request.rb +15 -4
  59. data/spec/support/spec_support.rb +3 -0
  60. data/spec/support/stubbing_using_allow.rb +1 -0
  61. data/spec/support/term.json +13 -1
  62. data/tasks/pact-test.rake +45 -26
  63. metadata +23 -13
  64. data/lib/pact/provider/client_project_pact_helper.rb +0 -4
  65. data/spec/lib/pact/provider/pact_spec_runner_spec.rb +0 -7
  66. data/spec/lib/pact/verification_task_spec.rb +0 -99
@@ -1,12 +1,12 @@
1
1
  require 'spec_helper'
2
- require 'pact/doc/markdown/interactions_renderer'
2
+ require 'pact/doc/markdown/consumer_contract_renderer'
3
3
 
4
4
  module Pact
5
5
  module Doc
6
6
  module Markdown
7
- describe InteractionsRenderer do
7
+ describe ConsumerContractRenderer do
8
8
 
9
- subject { InteractionsRenderer.new(consumer_contract) }
9
+ subject { ConsumerContractRenderer.new(consumer_contract) }
10
10
  let(:consumer_contract) { Pact::ConsumerContract.from_uri './spec/support/markdown_pact.json' }
11
11
 
12
12
  let(:expected_output) { File.read("./spec/support/generated_markdown.md") }
@@ -19,7 +19,7 @@ module Pact
19
19
 
20
20
  describe ".call" do
21
21
  it "renders an interaction" do
22
- expect(InteractionsRenderer.call consumer_contract).to eq(expected_output)
22
+ expect(ConsumerContractRenderer.call consumer_contract).to eq(expected_output)
23
23
  end
24
24
  end
25
25
 
@@ -54,7 +54,7 @@ EOF
54
54
  end
55
55
 
56
56
  it "generates the right number of lines, even with ActiveSupport loaded" do
57
- expect(line_count).to eq 10
57
+ expect(line_count).to eq 9
58
58
  end
59
59
 
60
60
  end
@@ -76,7 +76,7 @@ EOF
76
76
  end
77
77
 
78
78
  it "generates the right number of lines, even with ActiveSupport loaded" do
79
- expect(line_count).to eq 10
79
+ expect(line_count).to eq 9
80
80
  end
81
81
 
82
82
  end
@@ -98,7 +98,7 @@ EOF
98
98
  end
99
99
 
100
100
  it "generates the right number of lines, even with ActiveSupport loaded" do
101
- expect(line_count).to eq 6
101
+ expect(line_count).to eq 5
102
102
  end
103
103
 
104
104
  end
@@ -120,7 +120,7 @@ EOF
120
120
  end
121
121
 
122
122
  it "generates the right number of lines, even with ActiveSupport loaded" do
123
- expect(line_count).to eq 9
123
+ expect(line_count).to eq 8
124
124
  end
125
125
  end
126
126
 
@@ -140,7 +140,7 @@ EOF
140
140
  end
141
141
 
142
142
  it "generates the right number of lines, even with ActiveSupport loaded" do
143
- expect(line_count).to eq 9
143
+ expect(line_count).to eq 8
144
144
  end
145
145
 
146
146
  end
@@ -159,7 +159,7 @@ EOF
159
159
  end
160
160
 
161
161
  it "generates the right number of lines, even with ActiveSupport loaded" do
162
- expect(line_count).to eq 9
162
+ expect(line_count).to eq 8
163
163
  end
164
164
 
165
165
  end
@@ -185,7 +185,7 @@ EOF
185
185
  end
186
186
 
187
187
  it "generates the right number of lines, even with ActiveSupport loaded" do
188
- expect(line_count).to eq 9
188
+ expect(line_count).to eq 8
189
189
  end
190
190
 
191
191
  end
@@ -203,7 +203,7 @@ EOF
203
203
  end
204
204
 
205
205
  it "generates the right number of lines, even with ActiveSupport loaded" do
206
- expect(line_count).to eq 12
206
+ expect(line_count).to eq 11
207
207
  end
208
208
 
209
209
  end
@@ -14,12 +14,12 @@ module Pact
14
14
  describe "#color_enabled" do
15
15
 
16
16
  it "sets color_enabled to be true by default" do
17
- expect(subject.color_enabled).to be_true
17
+ expect(subject.color_enabled).to be true
18
18
  end
19
19
 
20
20
  it "allows configuration of colour_enabled" do
21
21
  subject.color_enabled = false
22
- expect(subject.color_enabled).to be_false
22
+ expect(subject.color_enabled).to be false
23
23
  end
24
24
 
25
25
  end
@@ -10,9 +10,11 @@ module Pact
10
10
  describe "#match_term_failure_message" do
11
11
 
12
12
  let(:message) { "line1\nline2"}
13
+ let(:output_message) { "Actual: actual\n\n#{message}"}
14
+ let(:output_message_with_resets) { "Actual: actual\n\n#{r}line1\n#{r}line2"}
13
15
  let(:r) { ::Term::ANSIColor.reset }
14
- let(:message_with_resets) { "#{r}line1\n#{r}line2"}
15
16
  let(:diff) { double("diff") }
17
+ let(:actual) { "actual" }
16
18
  let(:color_enabled) { true }
17
19
  let(:ansi_reset_at_start_of_line) { /^#{Regexp.escape ::Term::ANSIColor.reset}/ }
18
20
  let(:message_line_count) { message.split("\n").size }
@@ -21,7 +23,7 @@ module Pact
21
23
  allow(Pact.configuration.diff_formatter).to receive(:call).and_return(message)
22
24
  end
23
25
 
24
- subject { match_term_failure_message diff, color_enabled }
26
+ subject { match_term_failure_message diff, actual, color_enabled }
25
27
 
26
28
  it "creates a message using the configured diff_formatter" do
27
29
  expect(Pact.configuration.diff_formatter).to receive(:call).with(diff)
@@ -31,17 +33,26 @@ module Pact
31
33
  context "when color_enabled is true" do
32
34
 
33
35
  it "returns the message with ANSI reset at the start of each line" do
34
- expect(subject).to eq(message_with_resets)
36
+ expect(subject).to eq(output_message_with_resets)
35
37
  end
36
38
 
37
39
  end
38
40
 
41
+ context "when the actual is not a string" do
42
+
43
+ let(:actual) { {the: "actual"} }
44
+
45
+ it "includes the actual as json" do
46
+ expect(subject).to include(actual.to_json)
47
+ end
48
+ end
49
+
39
50
  context "when color_enabled is false" do
40
51
 
41
52
  let(:color_enabled) { false }
42
53
 
43
54
  it "returns the message unmodified" do
44
- expect(subject).to eq(message)
55
+ expect(subject).to eq(output_message)
45
56
  end
46
57
 
47
58
  end
@@ -88,9 +99,9 @@ module Pact
88
99
 
89
100
  end
90
101
 
91
- context "when the expected is a Pact::Term" do
102
+ context "when the expected is a regexp" do
92
103
 
93
- let(:expected) { Pact::Term.new(matcher: /hal/, generate: 'application/hal+json')}
104
+ let(:expected) { /hal/ }
94
105
  let(:expected_message) { "Expected header \"Content-Type\" to match /hal/, but was \"text/plain\"" }
95
106
 
96
107
  it "creates a message with the term's matcher" do
@@ -1,6 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'pact/provider/rspec/formatter'
3
3
  require './spec/support/factories'
4
+ require './spec/support/spec_support'
4
5
 
5
6
  module Pact
6
7
  module Provider
@@ -18,7 +19,8 @@ module Pact
18
19
  let(:missing_provider_states) { 'missing_provider_states'}
19
20
 
20
21
  subject { Formatter.new output }
21
- let(:output_result) { output.string }
22
+
23
+ let(:output_result) { Pact::SpecSupport.remove_ansicolor output.string }
22
24
 
23
25
  before do
24
26
  allow(PrintMissingProviderStates).to receive(:call)
@@ -79,7 +79,7 @@ module Pact
79
79
  end
80
80
 
81
81
  it "calls finalize" do
82
- expect(@test.finalized).to be_true
82
+ expect(@test.finalized).to be true
83
83
  end
84
84
  end
85
85
  end
@@ -72,6 +72,14 @@ module Pact
72
72
  expect(subject).to eq("GET /something")
73
73
  end
74
74
  end
75
+
76
+ context "with a query" do
77
+ subject { TestRequest.new("get", "/something", {}, {} , "test=query").method_and_path }
78
+
79
+ it "includes the query" do
80
+ expect(subject).to eq("GET /something?test=query")
81
+ end
82
+ end
75
83
  end
76
84
 
77
85
  end
@@ -1,80 +1,65 @@
1
1
  require 'spec_helper'
2
2
  require 'pact/tasks/task_helper'
3
+ require 'rake/file_utils'
3
4
 
4
5
  module Pact
5
6
  describe TaskHelper do
6
- include TaskHelper
7
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
8
 
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
9
+ describe ".execute_pact_verify" do
10
+ let(:ruby_path) { "/path/to/ruby" }
11
+ let(:pact_uri) { "/pact/uri" }
12
+ let(:default_pact_helper_path) { "/pact/helper/path.rb" }
20
13
 
21
- shared_context 'PACT_PROVIDER_STATE is defined' do
22
14
  before do
23
- ENV.stub(:[])
24
- ENV.stub(:[]).with("PACT_PROVIDER_STATE").and_return(env_provider_state)
15
+ stub_const("FileUtils::RUBY", ruby_path)
16
+ allow(Pact::Provider::PactHelperLocater).to receive(:pact_helper_path).and_return(default_pact_helper_path)
25
17
  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
18
 
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
19
+ context "with no pact_helper or pact URI" do
20
+ let(:command) { "#{ruby_path} -S pact verify -h #{default_pact_helper_path}" }
21
+ it "executes the command" do
22
+ expect(TaskHelper).to receive(:execute_cmd).with(command)
23
+ TaskHelper.execute_pact_verify
46
24
  end
25
+ end
47
26
 
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
27
+ context "with a pact URI" do
28
+ let(:command) { "#{ruby_path} -S pact verify -h #{default_pact_helper_path} -p #{pact_uri}" }
29
+ it "executes the command" do
30
+ expect(TaskHelper).to receive(:execute_cmd).with(command)
31
+ TaskHelper.execute_pact_verify(pact_uri)
52
32
  end
53
33
  end
54
34
 
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
35
+ context "with a pact URI and a pact_helper" do
36
+ let(:custom_pact_helper_path) { '/custom/pact_helper.rb' }
37
+ let(:command) { "#{ruby_path} -S pact verify -h #{custom_pact_helper_path} -p #{pact_uri}" }
38
+ it "executes the command" do
39
+ expect(TaskHelper).to receive(:execute_cmd).with(command)
40
+ TaskHelper.execute_pact_verify(pact_uri, custom_pact_helper_path)
65
41
  end
66
42
  end
67
43
 
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('')
44
+ context "with a pact_helper with no .rb on the end" do
45
+ let(:custom_pact_helper_path) { '/custom/pact_helper' }
46
+ let(:command) { "#{ruby_path} -S pact verify -h #{custom_pact_helper_path}.rb -p #{pact_uri}" }
47
+ it "executes the command" do
48
+ expect(TaskHelper).to receive(:execute_cmd).with(command)
49
+ TaskHelper.execute_pact_verify(pact_uri, custom_pact_helper_path)
72
50
  end
51
+ end
73
52
 
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
53
+ context "with a pact URI and a nil pact_helper" do
54
+ let(:command) { "#{ruby_path} -S pact verify -h #{default_pact_helper_path} -p #{pact_uri}" }
55
+ it "executes the command" do
56
+ expect(TaskHelper).to receive(:execute_cmd).with(command)
57
+ TaskHelper.execute_pact_verify(pact_uri, nil)
76
58
  end
77
59
  end
60
+
78
61
  end
62
+
63
+
79
64
  end
80
65
  end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+ require 'pact/tasks/verification_task'
3
+
4
+ module Pact
5
+ describe VerificationTask do
6
+ before :all do
7
+ @pact_helper = '/custom/path/pact_helper .rb'
8
+ @pact_uri = 'http://example.org/pact.json'
9
+ @task_name = 'pact:verify:pact_rake_spec'
10
+ @task_name_with_explict_pact_helper = 'pact:verify:pact_rake_spec_with_explict_pact_helper'
11
+ @consumer = 'some-consumer'
12
+ @criteria = {:description => /wiffle/}
13
+
14
+ VerificationTask.new(:pact_rake_spec_with_explict_pact_helper) do | pact |
15
+ pact.uri @pact_uri, pact_helper: @pact_helper
16
+ end
17
+
18
+ VerificationTask.new(:pact_rake_spec) do | pact |
19
+ pact.uri @pact_uri
20
+ end
21
+ end
22
+
23
+ before do
24
+ allow(Pact::TaskHelper).to receive(:execute_pact_verify).and_return(0)
25
+ end
26
+
27
+ let(:exit_code) {0}
28
+
29
+
30
+ describe '.initialize' do
31
+ context 'with an explict pact_helper' do
32
+ it 'creates the tasks' do
33
+ Rake::Task.tasks.should include_task @task_name
34
+ end
35
+ end
36
+ context 'with no explict pact_helper' do
37
+ it 'creates the tasks' do
38
+ Rake::Task.tasks.should include_task @task_name_with_explict_pact_helper
39
+ end
40
+ end
41
+ end
42
+
43
+ describe 'execute' do
44
+
45
+ context "with no explicit pact_helper" do
46
+ it 'verifies the pacts using the TaskHelper' do
47
+ expect(Pact::TaskHelper).to receive(:execute_pact_verify).with(@pact_uri, nil)
48
+ Rake::Task[@task_name].execute
49
+ end
50
+ end
51
+
52
+ context "with an explict pact_helper" do
53
+ let(:verification_config) { [ uri: @pact_uri, pact_helper: @pact_helper] }
54
+ it 'verifies the pacts using the TaskHelper' do
55
+ expect(Pact::TaskHelper).to receive(:execute_pact_verify).with(@pact_uri, @pact_helper)
56
+ Rake::Task[@task_name_with_explict_pact_helper].execute
57
+ end
58
+ end
59
+
60
+ context 'when all specs pass' do
61
+
62
+ it 'does not raise an exception' do
63
+ Rake::Task[@task_name].execute
64
+ end
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+
71
+ RSpec::Matchers.define :include_task do |expected|
72
+ match do |actual|
73
+ actual.any? { |task| task.name == expected }
74
+ end
75
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'pact/consumer/request'
3
+ require 'pact/consumer_contract/request'
4
+
5
+ PACT_SPEC_DIR = "../pact-specification/testcases"
6
+ REQUEST_TEST_CASE_FOLDERS = Dir.glob("#{PACT_SPEC_DIR}/request/**")
7
+ REQUEST_TEST_CASE_FILES = Dir.glob("#{PACT_SPEC_DIR}/request/**/*.json")
8
+
9
+ TEST_DESCRIPTIONS = {true => "matches", false => "does not match"}
10
+
11
+ describe "Pact gem complicance with Pact Specification 1.0.0" do
12
+
13
+ directories = Dir.glob("#{PACT_SPEC_DIR}/*")
14
+
15
+ directories.each do | dir_name |
16
+
17
+ describe File.basename(dir_name) do
18
+
19
+ sub_directories = Dir.glob("#{dir_name}/*")
20
+
21
+ sub_directories.each do | sub_dir_name |
22
+
23
+ context File.basename(sub_dir_name) do
24
+ testcases = Dir.glob("#{sub_dir_name}/**/*.json")
25
+
26
+ testcases.each do | file_name |
27
+
28
+ context File.basename(file_name).chomp(".json") do
29
+
30
+ file_content = JSON.parse(File.read(file_name))
31
+ expected = Pact::Request::Expected.from_hash(file_content["expected"])
32
+ actual = Pact::Consumer::Request::Actual.from_hash(file_content["actual"])
33
+ expected_result = file_content.fetch("match")
34
+ comment = file_content["comment"]
35
+
36
+ it "#{TEST_DESCRIPTIONS[expected_result]} - #{comment}" do
37
+ expect(expected.matches?(actual)).to eq expected_result
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end