pact_broker 2.27.6 → 2.29.0

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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.travis.yml +1 -2
  4. data/CHANGELOG.md +38 -0
  5. data/MATRIX.md +4 -0
  6. data/README.md +3 -2
  7. data/Rakefile +1 -2
  8. data/config/database.yml +5 -0
  9. data/lib/pact_broker/api/decorators/matrix_decorator.rb +7 -1
  10. data/lib/pact_broker/api/decorators/reason_decorator.rb +50 -0
  11. data/lib/pact_broker/api/resources/base_resource.rb +1 -1
  12. data/lib/pact_broker/api/resources/error_handler.rb +32 -9
  13. data/lib/pact_broker/app.rb +16 -1
  14. data/lib/pact_broker/domain/webhook_request.rb +1 -1
  15. data/lib/pact_broker/matrix/deployment_status_summary.rb +123 -44
  16. data/lib/pact_broker/matrix/head_row.rb +20 -0
  17. data/lib/pact_broker/matrix/integration.rb +49 -7
  18. data/lib/pact_broker/matrix/query_results.rb +3 -2
  19. data/lib/pact_broker/matrix/query_results_with_deployment_status_summary.rb +2 -2
  20. data/lib/pact_broker/matrix/reason.rb +74 -0
  21. data/lib/pact_broker/matrix/repository.rb +97 -61
  22. data/lib/pact_broker/matrix/resolved_selector.rb +126 -0
  23. data/lib/pact_broker/matrix/row.rb +8 -1
  24. data/lib/pact_broker/matrix/service.rb +2 -16
  25. data/lib/pact_broker/pacts/repository.rb +15 -5
  26. data/lib/pact_broker/repositories/helpers.rb +3 -2
  27. data/lib/pact_broker/ui/views/index/_navbar.haml +14 -0
  28. data/lib/pact_broker/ui/views/index/show-with-tags.haml +1 -12
  29. data/lib/pact_broker/ui/views/index/show.haml +1 -12
  30. data/lib/pact_broker/ui/views/layouts/main.haml +3 -0
  31. data/lib/pact_broker/version.rb +1 -1
  32. data/lib/pact_broker/webhooks/job.rb +11 -5
  33. data/lib/pact_broker/webhooks/service.rb +10 -2
  34. data/lib/pact_broker/webhooks/webhook.rb +4 -0
  35. data/lib/rack/pact_broker/database_transaction.rb +22 -0
  36. data/pact_broker.gemspec +25 -1
  37. data/script/restart.sh +18 -0
  38. data/script/watch.sh +7 -0
  39. data/spec/features/publish_verification_spec.rb +1 -1
  40. data/spec/integration/app_spec.rb +1 -1
  41. data/spec/integration/webhooks/certificate_spec.rb +10 -2
  42. data/spec/lib/pact_broker/api/decorators/matrix_decorator_spec.rb +2 -1
  43. data/spec/lib/pact_broker/api/decorators/reason_decorator_spec.rb +59 -0
  44. data/spec/lib/pact_broker/api/resources/error_handler_spec.rb +84 -21
  45. data/spec/lib/pact_broker/app_spec.rb +22 -0
  46. data/spec/lib/pact_broker/domain/webhook_request_spec.rb +1 -1
  47. data/spec/lib/pact_broker/matrix/deployment_status_summary_spec.rb +116 -28
  48. data/spec/lib/pact_broker/matrix/head_row_spec.rb +23 -0
  49. data/spec/lib/pact_broker/matrix/integration_spec.rb +242 -0
  50. data/spec/lib/pact_broker/matrix/repository_dependency_spec.rb +58 -0
  51. data/spec/lib/pact_broker/matrix/repository_spec.rb +40 -7
  52. data/spec/lib/pact_broker/matrix/service_spec.rb +0 -50
  53. data/spec/lib/pact_broker/pacts/repository_spec.rb +20 -4
  54. data/spec/lib/pact_broker/webhooks/job_spec.rb +9 -9
  55. data/spec/lib/pact_broker/webhooks/service_spec.rb +3 -3
  56. data/spec/lib/pact_broker/webhooks/webhook_spec.rb +39 -0
  57. data/spec/lib/rack/pact_broker/database_transaction_spec.rb +40 -0
  58. data/spec/service_consumers/pact_helper.rb +2 -0
  59. data/spec/spec_helper.rb +2 -3
  60. data/spec/support/jobs.rb +12 -0
  61. data/spec/support/migration_helpers.rb +1 -1
  62. data/spec/support/simplecov.rb +10 -0
  63. data/tasks/audit.rake +2 -0
  64. data/tasks/pact.rake +5 -1
  65. data/tasks/rspec.rake +14 -0
  66. metadata +50 -5
  67. data/db/pact_broker_database.sqlite3 +0 -0
  68. data/spec/lib/pact_broker/matrix/repository_find_integrations_spec.rb +0 -51
data/script/restart.sh ADDED
@@ -0,0 +1,18 @@
1
+ #/bin/bash
2
+
3
+ root_dir=$(cd "$(dirname "$0")/.." && pwd)
4
+ example_dir="${root_dir}/example"
5
+ APP_DIR="${APP_DIR:-${example_dir}}"
6
+
7
+ cd "${APP_DIR}"
8
+
9
+ if [ -f .pid ]; then
10
+ pid=$(cat .pid)
11
+ echo "Pid is ${pid}"
12
+ kill $pid
13
+ sleep 2
14
+ fi
15
+
16
+ bundle exec rackup &
17
+ pid=$!
18
+ echo $pid > .pid
data/script/watch.sh ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+
3
+ relative_app_dir=${1:-$PWD}
4
+ export APP_DIR=$(cd $relative_app_dir && pwd)
5
+ root_dir=$(cd "$(dirname "$0")/.." && pwd)
6
+ "${root_dir}"/script/restart.sh &
7
+ fswatch -o "${root_dir}/lib" | xargs -n1 -I{} "${root_dir}/script/restart.sh"
@@ -45,7 +45,7 @@ describe "Recording a pact verification" do
45
45
  expect(JSON.parse(subject.body)).to include JSON.parse(verification_content)
46
46
  end
47
47
 
48
- context "with a webhook configured" do
48
+ context "with a webhook configured", job: true do
49
49
  before do
50
50
  td.create_webhook(
51
51
  method: 'POST',
@@ -31,7 +31,7 @@ module PactBroker
31
31
  context "when Accept includes text/html" do
32
32
  let(:env) { {'HTTP_ACCEPT' => 'text/html'} }
33
33
 
34
- subject { get path, '', env; last_response.tap { |it| File.open("bethtest.html", "w") { |file| file << it.body } } }
34
+ subject { get path, '', env; last_response }
35
35
 
36
36
  describe "a request for root" do
37
37
 
@@ -1,13 +1,21 @@
1
1
  require 'pact_broker/domain/webhook_request'
2
+ require 'faraday'
2
3
  # certificates and key generated by script/generate-certificates-for-webooks-certificate-spec.rb
3
4
 
4
5
  describe "executing a webhook to a server with a self signed certificate" do
5
- let(:td) { TestDataBuilder.new }
6
+ def wait_for_server_to_start
7
+ Faraday.new(url: "https://localhost:4444", ssl: {verify: false}) do |builder|
8
+ builder.request :retry, max: 20, interval: 0.5, exceptions: [StandardError]
9
+ builder.adapter :net_http
10
+ end.get
11
+ end
12
+
6
13
  before(:all) do
7
14
  @pipe = IO.popen("bundle exec ruby spec/support/ssl_webhook_server.rb")
8
- sleep 3
15
+ wait_for_server_to_start
9
16
  end
10
17
 
18
+ let(:td) { TestDataBuilder.new }
11
19
  let(:webhook_request) do
12
20
  PactBroker::Domain::WebhookRequest.new(
13
21
  method: 'get',
@@ -101,8 +101,9 @@ module PactBroker
101
101
  }
102
102
  end
103
103
 
104
- let(:query_results){ PactBroker::Matrix::QueryResultsWithDeploymentStatusSummary.new([row_1, row_2], selectors, options, resolved_selectors, deployment_status_summary)}
104
+ let(:query_results){ PactBroker::Matrix::QueryResultsWithDeploymentStatusSummary.new([row_1, row_2], selectors, options, resolved_selectors, integrations, deployment_status_summary)}
105
105
  let(:selectors) { nil }
106
+ let(:integrations){ [] }
106
107
  let(:options) { nil }
107
108
  let(:resolved_selectors) { nil }
108
109
  let(:counts) { { success: 1 } }
@@ -0,0 +1,59 @@
1
+ require 'pact_broker/api/decorators/reason_decorator'
2
+ require 'pact_broker/matrix/reason'
3
+
4
+ module PactBroker
5
+ module Api
6
+ module Decorators
7
+ describe ReasonDecorator do
8
+
9
+ REASON_CLASSES = ObjectSpace.each_object(Class).select { |klass| klass < PactBroker::Matrix::Reason }
10
+
11
+ describe "the number of Reason classes" do
12
+ it "is 9 - add another spec here if a new Reason is added" do
13
+ expect(REASON_CLASSES.size).to eq 9
14
+ end
15
+ end
16
+
17
+ describe "#to_s" do
18
+
19
+ let(:consumer_selector) { double('consumer selector', description: "version 2 of Foo") }
20
+ let(:provider_selector) { double('provider selector', description: "version 6 of Bar") }
21
+ let(:selectors) { [consumer_selector, provider_selector] }
22
+
23
+ subject { ReasonDecorator.new(reason) }
24
+
25
+ context "when the reason is PactBroker::Matrix::PactNotEverVerifiedByProvider" do
26
+ let(:reason) { PactBroker::Matrix::PactNotEverVerifiedByProvider.new(*selectors) }
27
+ let(:provider_selector) { double('provider selector', description: "any version of Bar") }
28
+
29
+ its(:to_s) { is_expected.to eq "There is no verified pact between version 2 of Foo and any version of Bar" }
30
+ end
31
+
32
+ context "when the reason is PactBroker::Matrix::PactNotVerifiedByRequiredProviderVersion" do
33
+ let(:reason) { PactBroker::Matrix::PactNotVerifiedByRequiredProviderVersion.new(*selectors) }
34
+
35
+ its(:to_s) { is_expected.to eq "There is no verified pact between version 2 of Foo and version 6 of Bar" }
36
+ end
37
+
38
+ context "when the reason is PactBroker::Matrix::VerificationFailed" do
39
+ let(:reason) { PactBroker::Matrix::VerificationFailed.new(*selectors) }
40
+
41
+ its(:to_s) { is_expected.to eq "The verification between version 2 of Foo and version 6 of Bar failed" }
42
+ end
43
+
44
+ context "when the reason is PactBroker::Matrix::NoDependenciesMissing" do
45
+ let(:reason) { PactBroker::Matrix::NoDependenciesMissing.new }
46
+
47
+ its(:to_s) { is_expected.to eq "There are no missing dependencies" }
48
+ end
49
+
50
+ context "when the reason is PactBroker::Matrix::Successful" do
51
+ let(:reason) { PactBroker::Matrix::Successful.new }
52
+
53
+ its(:to_s) { is_expected.to eq "All required verification results are published and successful" }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -8,12 +8,13 @@ module PactBroker
8
8
 
9
9
  before do
10
10
  allow(ErrorHandler).to receive(:logger).and_return(logger)
11
+ allow(SecureRandom).to receive(:urlsafe_base64).and_return("bYWfn-+yWPlf")
11
12
  end
12
13
 
13
14
  let(:logger) { double('logger').as_null_object }
14
15
  let(:error) { StandardError.new('test error') }
15
16
  let(:thing) { double('thing', call: nil, another_call: nil) }
16
- let(:options) { { env: env } }
17
+ let(:options) { { env: env, error_reference: "bYWfnyWPlf" } }
17
18
  let(:request) { double('request' ) }
18
19
  let(:response) { double('response', :body= => nil) }
19
20
  let(:env) { double('env') }
@@ -37,33 +38,59 @@ module PactBroker
37
38
  subject
38
39
  end
39
40
 
40
- context "when the error is a PactBroker::Error or subclass" do
41
- let(:error) { Class.new(PactBroker::Error).new('test error') }
42
-
43
- it "does not invoke the api error reporters" do
44
- expect(thing).to_not receive(:call).with(error, options)
45
- subject
46
- end
47
- end
48
-
49
- it "creates a json error response body" do
41
+ it "includes an error reference" do
50
42
  expect(response).to receive(:body=) do | body |
51
- expect(JSON.parse(body)['error']).to include 'message' => 'test error'
43
+ expect(JSON.parse(body)['error']).to include 'reference' => "bYWfnyWPlf"
52
44
  end
53
45
  subject
54
46
  end
55
47
 
56
-
57
48
  context "when show_backtrace_in_error_response? is true" do
58
49
  before do
59
50
  allow(PactBroker.configuration).to receive(:show_backtrace_in_error_response?).and_return(true)
60
51
  end
61
52
 
62
- it "includes the backtrace in the error response" do
63
- expect(response).to receive(:body=) do | body |
64
- expect(body).to include("backtrace")
53
+ context "when the error is a PactBroker::Error or subclass" do
54
+ let(:error) { Class.new(PactBroker::Error).new('test error') }
55
+
56
+ it "does not invoke the api error reporters" do
57
+ expect(thing).to_not receive(:call).with(error, options)
58
+ subject
59
+ end
60
+
61
+ it "uses the error message as the message" do
62
+ expect(response).to receive(:body=) do | body |
63
+ expect(JSON.parse(body)['error']).to include 'message' => "test error"
64
+ end
65
+ subject
66
+ end
67
+
68
+ it "includes the backtrace in the error response" do
69
+ expect(response).to receive(:body=) do | body |
70
+ expect(body).to include("backtrace")
71
+ end
72
+ subject
73
+ end
74
+ end
75
+ context "when the error is not a PactBroker::Error or subclass" do
76
+ it "invokes the api error reporters" do
77
+ expect(thing).to receive(:call).with(error, options)
78
+ subject
79
+ end
80
+
81
+ it "uses the error message as the message" do
82
+ expect(response).to receive(:body=) do | body |
83
+ expect(JSON.parse(body)['error']).to include 'message' => "test error"
84
+ end
85
+ subject
86
+ end
87
+
88
+ it "includes the backtrace in the error response" do
89
+ expect(response).to receive(:body=) do | body |
90
+ expect(body).to include("backtrace")
91
+ end
92
+ subject
65
93
  end
66
- subject
67
94
  end
68
95
  end
69
96
 
@@ -72,11 +99,47 @@ module PactBroker
72
99
  allow(PactBroker.configuration).to receive(:show_backtrace_in_error_response?).and_return(false)
73
100
  end
74
101
 
75
- it "does not include the backtrace in the error response" do
76
- expect(response).to receive(:body=) do | body |
77
- expect(body).to_not include("backtrace")
102
+ context "when the error is a PactBroker::Error or subclass" do
103
+ let(:error) { Class.new(PactBroker::Error).new('test error') }
104
+
105
+ it "does not invoke the api error reporters" do
106
+ expect(thing).to_not receive(:call).with(error, options)
107
+ subject
108
+ end
109
+
110
+ it "uses the error message as the message" do
111
+ expect(response).to receive(:body=) do | body |
112
+ expect(JSON.parse(body)['error']).to include 'message' => "test error"
113
+ end
114
+ subject
115
+ end
116
+
117
+ it "does not include the backtrace in the error response" do
118
+ expect(response).to receive(:body=) do | body |
119
+ expect(body).to_not include("backtrace")
120
+ end
121
+ subject
122
+ end
123
+ end
124
+ context "when the error is not a PactBroker::Error or subclass" do
125
+ it "invokes the api error reporters" do
126
+ expect(thing).to receive(:call).with(error, options)
127
+ subject
128
+ end
129
+
130
+ it "uses a hardcoded error message" do
131
+ expect(response).to receive(:body=) do | body |
132
+ expect(JSON.parse(body)['error']['message']).to match /An error/
133
+ end
134
+ subject
135
+ end
136
+
137
+ it "does not include the backtrace in the error response" do
138
+ expect(response).to receive(:body=) do | body |
139
+ expect(body).to_not include("backtrace")
140
+ end
141
+ subject
78
142
  end
79
- subject
80
143
  end
81
144
  end
82
145
 
@@ -65,6 +65,28 @@ module PactBroker
65
65
  end
66
66
  end
67
67
 
68
+ describe "use_custom_ui" do
69
+ context "when the UI returns a non 404 response" do
70
+ let(:custom_ui) { double('ui', call: [200, {}, ["hello"]]) }
71
+
72
+ it "returns the given page" do
73
+ app.use_custom_ui(custom_ui)
74
+
75
+ get "/", nil, { "HTTP_ACCEPT" => "text/html" }
76
+ expect(last_response.body).to eq "hello"
77
+ end
78
+ end
79
+
80
+ context "when the UI returns a 404 response" do
81
+ let(:custom_ui) { double('ui', call: [404, {}, []]) }
82
+
83
+ it "passes on the call to the rest of the app" do
84
+ get "/", nil, { "HTTP_ACCEPT" => "text/html" }
85
+ expect(last_response.status).to eq 200
86
+ end
87
+ end
88
+ end
89
+
68
90
  describe "use_xxx_auth" do
69
91
  class TestAuth
70
92
  def initialize app, *args, &block
@@ -310,7 +310,7 @@ module PactBroker
310
310
  end
311
311
 
312
312
  it "logs the error" do
313
- expect(logger).to receive(:error).with(/Error.*WebhookTestError.*blah/)
313
+ expect(logger).to receive(:info).with(/Error.*WebhookTestError.*blah/)
314
314
  execute
315
315
  end
316
316
 
@@ -2,6 +2,7 @@ require 'pact_broker/matrix/deployment_status_summary'
2
2
  require 'pact_broker/matrix/row'
3
3
  require 'pact_broker/matrix/query_results'
4
4
  require 'pact_broker/matrix/integration'
5
+ require 'pact_broker/matrix/resolved_selector'
5
6
 
6
7
  module PactBroker
7
8
  module Matrix
@@ -17,21 +18,33 @@ module PactBroker
17
18
  let(:rows) { [row_1, row_2] }
18
19
  let(:row_1) do
19
20
  double(Row,
21
+ consumer: foo,
22
+ provider: bar,
23
+ consumer_version: foo_version,
24
+ provider_version: bar_version,
20
25
  consumer_name: "Foo",
21
26
  consumer_id: 1,
27
+ consumer_version_id: 1,
22
28
  provider_name: "Bar",
23
29
  provider_id: 2,
24
- success: row_1_success
30
+ success: row_1_success,
31
+ pacticipant_names: %w{Foo Bar}
25
32
  )
26
33
  end
27
34
 
28
35
  let(:row_2) do
29
36
  double(Row,
37
+ consumer: foo,
38
+ provider: baz,
39
+ consumer_version: foo_version,
40
+ provider_version: baz_version,
30
41
  consumer_name: "Foo",
31
42
  consumer_id: 1,
43
+ consumer_version_id: 1,
32
44
  provider_name: "Baz",
33
45
  provider_id: 3,
34
- success: true
46
+ success: true,
47
+ pacticipant_names: %w{Foo Baz}
35
48
  )
36
49
  end
37
50
 
@@ -39,22 +52,38 @@ module PactBroker
39
52
 
40
53
  let(:integrations) do
41
54
  [
42
- Integration.new(1, "Foo", 2, "Bar"),
43
- Integration.new(1, "Foo", 3, "Baz")
55
+ Integration.new(1, "Foo", 2, "Bar", true),
56
+ Integration.new(1, "Foo", 3, "Baz", true)
44
57
  ]
45
58
  end
46
59
 
60
+ let(:foo) { double('foo', id: 1, name: "Foo") }
61
+ let(:bar) { double('bar', id: 2, name: "Bar") }
62
+ let(:baz) { double('baz', id: 3, name: "Baz") }
63
+ let(:foo_version) { double('foo version', number: "ddec8101dabf4edf9125a69f9a161f0f294af43c", id: 10)}
64
+ let(:bar_version) { double('bar version', number: "14131c5da3abf323ccf410b1b619edac76231243", id: 10)}
65
+ let(:baz_version) { double('baz version', number: "4ee06460f10e8207ad904fa9fa6c4842e462ab59", id: 10)}
66
+
47
67
  let(:resolved_selectors) do
48
68
  [
49
- {
50
- pacticipant_id: 1, pacticipant_version_number: "ddec8101dabf4edf9125a69f9a161f0f294af43c"
51
- },
52
- {
53
- pacticipant_id: 2, pacticipant_version_number: "14131c5da3abf323ccf410b1b619edac76231243"
54
- },
55
- {
56
- pacticipant_id: 3, pacticipant_version_number: "4ee06460f10e8207ad904fa9fa6c4842e462ab59"
57
- }
69
+ ResolvedSelector.new(
70
+ pacticipant_id: 1,
71
+ pacticipant_name: "Foo",
72
+ pacticipant_version_number: "ddec8101dabf4edf9125a69f9a161f0f294af43c",
73
+ pacticipant_version_id: 10
74
+ ),
75
+ ResolvedSelector.new(
76
+ pacticipant_id: 2,
77
+ pacticipant_name: "Bar",
78
+ pacticipant_version_number: "14131c5da3abf323ccf410b1b619edac76231243",
79
+ pacticipant_version_id: 11
80
+ ),
81
+ ResolvedSelector.new(
82
+ pacticipant_id: 3,
83
+ pacticipant_name: "Baz",
84
+ pacticipant_version_number: "4ee06460f10e8207ad904fa9fa6c4842e462ab59",
85
+ pacticipant_version_id: 12
86
+ ),
58
87
  ]
59
88
  end
60
89
 
@@ -62,7 +91,7 @@ module PactBroker
62
91
 
63
92
  context "when there is a row for all integrations" do
64
93
  its(:deployable?) { is_expected.to be true }
65
- its(:reasons) { is_expected.to eq ["All verification results are published and successful"] }
94
+ its(:reasons) { is_expected.to eq [Successful.new] }
66
95
  its(:counts) { is_expected.to eq success: 2, failed: 0, unknown: 0 }
67
96
  end
68
97
 
@@ -70,7 +99,12 @@ module PactBroker
70
99
  let(:rows) { [] }
71
100
 
72
101
  its(:deployable?) { is_expected.to be nil }
73
- its(:reasons) { is_expected.to eq ["No results matched the given query"] }
102
+ its(:reasons) do
103
+ is_expected.to eq [
104
+ PactNotVerifiedByRequiredProviderVersion.new(resolved_selectors.first, resolved_selectors[1]),
105
+ PactNotVerifiedByRequiredProviderVersion.new(resolved_selectors.first, resolved_selectors.last)
106
+ ]
107
+ end
74
108
  its(:counts) { is_expected.to eq success: 0, failed: 0, unknown: 2 }
75
109
  end
76
110
 
@@ -78,7 +112,7 @@ module PactBroker
78
112
  let(:row_1_success) { nil }
79
113
 
80
114
  its(:deployable?) { is_expected.to be nil }
81
- its(:reasons) { is_expected.to eq ["Missing one or more verification results"] }
115
+ its(:reasons) { is_expected.to eq [PactNotEverVerifiedByProvider.new(resolved_selectors.first, resolved_selectors[1]) ] }
82
116
  its(:counts) { is_expected.to eq success: 1, failed: 0, unknown: 1 }
83
117
  end
84
118
 
@@ -86,36 +120,90 @@ module PactBroker
86
120
  let(:row_1_success) { false }
87
121
 
88
122
  its(:deployable?) { is_expected.to be false }
89
- its(:reasons) { is_expected.to eq ["One or more verifications have failed"] }
123
+ its(:reasons) { is_expected.to eq [VerificationFailed.new(resolved_selectors.first, resolved_selectors[1])] }
90
124
  its(:counts) { is_expected.to eq success: 1, failed: 1, unknown: 0 }
91
125
  end
92
126
 
93
- context "when there is a relationship missing" do
127
+ context "when there is a provider relationship missing" do
94
128
  let(:rows) { [row_1] }
95
129
 
96
130
  its(:deployable?) { is_expected.to be nil }
97
- its(:reasons) { is_expected.to eq ["There is no verified pact between Foo (ddec8101dabf4edf9125a69f9a161f0f294af43c) and Baz (4ee06460f10e8207ad904fa9fa6c4842e462ab59)"] }
131
+ its(:reasons) { is_expected.to eq [PactNotVerifiedByRequiredProviderVersion.new(resolved_selectors.first, resolved_selectors.last)] }
98
132
  its(:counts) { is_expected.to eq success: 1, failed: 0, unknown: 1 }
99
133
  end
100
134
 
101
- context "when there is something unexpected about the data and the resolved selector cannot be found" do
135
+ context "when there is a consumer integration missing and only the provider was specified in the query" do
136
+ let(:rows) { [row_1] }
137
+ let(:integrations) do
138
+ [
139
+ Integration.new(1, "Foo", 2, "Bar", true),
140
+ Integration.new(3, "Baz", 2, "Bar", false) # the missing one
141
+ ]
142
+ end
143
+
144
+ its(:deployable?) { is_expected.to be true }
145
+ its(:reasons) { is_expected.to eq [Successful.new] }
146
+ its(:counts) { is_expected.to eq success: 1, failed: 0, unknown: 0 }
147
+ end
148
+
149
+ context "when there are no rows, and no missing downstream providers and the provider was specified in the query" do
150
+ let(:rows) { [] }
151
+ let(:integrations) do
152
+ [
153
+ Integration.new(1, "Foo", 2, "Bar", false),
154
+ Integration.new(3, "Baz", 2, "Bar", false)
155
+ ]
156
+ end
157
+
158
+ its(:deployable?) { is_expected.to be true }
159
+ its(:reasons) { is_expected.to eq [NoDependenciesMissing.new] }
160
+ its(:counts) { is_expected.to eq success: 0, failed: 0, unknown: 0 }
161
+ end
162
+
163
+ context "when there is a provider integration missing and only the consumer was specified in the query" do
102
164
  let(:rows) { [row_1] }
103
165
 
104
- let(:resolved_selectors) do
166
+ let(:integrations) do
105
167
  [
106
- {
107
- pacticipant_id: 3, pacticipant_version_number: "4ee06460f10e8207ad904fa9fa6c4842e462ab59"
108
- }
168
+ Integration.new(1, "Foo", 2, "Bar", true),
169
+ Integration.new(1, "Foo", 3, "Baz", true) # the missing one
109
170
  ]
110
171
  end
111
172
 
112
173
  its(:deployable?) { is_expected.to be nil }
113
- its(:reasons) { is_expected.to eq ["There is no verified pact between Foo (unresolved version) and Baz (4ee06460f10e8207ad904fa9fa6c4842e462ab59)"] }
174
+ its(:reasons) { is_expected.to eq [PactNotVerifiedByRequiredProviderVersion.new(resolved_selectors.first, resolved_selectors.last)] }
175
+ its(:counts) { is_expected.to eq success: 1, failed: 0, unknown: 1 }
176
+ end
114
177
 
115
- it "logs a warning" do
116
- expect(logger).to receive(:warn).with(/Could not find the resolved version/)
117
- subject.reasons
178
+ context "when there are no inferred selectors and the pact has not ever been verified" do
179
+ # This happens when the user has not specified a version of the provider (eg no 'latest' and/or 'tag')
180
+ # so the "add inferred selectors" code in the Matrix::Repository has not run
181
+ # AND the pact has not been verified
182
+ # eg.
183
+ # bundle exec bin/pact-broker can-i-deploy --broker-base-url http://localhost:9292 --pacticipant Foo --version 1.1.0
184
+ let(:rows) { [row_1] }
185
+ let(:row_1_success) { nil }
186
+
187
+ let(:dummy_selector) do
188
+ ResolvedSelector.new(
189
+ pacticipant_id: 2,
190
+ pacticipant_name: "Bar",
191
+ pacticipant_version_id: 10,
192
+ pacticipant_version_number: "14131c5da3abf323ccf410b1b619edac76231243",
193
+ latest: nil,
194
+ tag: nil,
195
+ type: :inferred
196
+ )
118
197
  end
198
+
199
+ before do
200
+ resolved_selectors.delete_at(1)
201
+ resolved_selectors.delete_at(1)
202
+ integrations.delete_at(1)
203
+ end
204
+
205
+ its(:deployable?) { is_expected.to be nil }
206
+ its(:reasons) { is_expected.to eq [PactNotEverVerifiedByProvider.new(resolved_selectors.first, dummy_selector)] }
119
207
  end
120
208
  end
121
209
  end