Skip to content

Commit 7f91710

Browse files
committed
feat(matrix): add validation errors to matrix resource
1 parent 531e087 commit 7f91710

File tree

7 files changed

+139
-12
lines changed

7 files changed

+139
-12
lines changed

lib/pact_broker/api/resources/matrix.rb

+13-9
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,34 @@ def allowed_methods
1515
["GET"]
1616
end
1717

18-
def resource_exists?
19-
true
18+
def malformed_request?
19+
error_messages = matrix_service.validate_selectors(selectors)
20+
if error_messages.any?
21+
set_json_validation_error_messages error_messages
22+
true
23+
else
24+
false
25+
end
2026
end
2127

2228
def to_json
23-
versions = version_service.find_versions_by_selector(version_selectors)
24-
criteria = versions.each_with_object({}) { | version, hash | hash[version.pacticipant.name] = version.number }
29+
criteria = selected_versions.each_with_object({}) { | version, hash | hash[version.pacticipant.name] = version.number }
2530
lines = matrix_service.find_compatible_pacticipant_versions(criteria)
2631
PactBroker::Api::Decorators::MatrixPactDecorator.new(lines).to_json(user_options: { base_url: base_url })
2732
end
2833

2934
def selectors
30-
@selectors ||= CGI.parse(request.uri.query)['selector[]']
35+
@selectors ||= CGI.parse(CGI.unescape(request.uri.query))['selectors[]']
3136
end
3237

3338
def version_selectors
3439
@version_selectors ||= selectors.select{ | selector| selector.include?("/version/") }
3540
end
3641

37-
def pacticipant_selectors
38-
@pacticipant_selectors ||= selectors.select{ | selector | selectors.include?("/version/")}
42+
def selected_versions
43+
@selected_versions ||= version_service.find_versions_by_selector(version_selectors)
3944
end
40-
4145
end
4246
end
4347
end
44-
end
48+
end

lib/pact_broker/matrix/service.rb

+32-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
module PactBroker
44
module Matrix
55
module Service
6-
extend self
6+
VERSION_SELECTOR_PATTERN = %r{(^[^/]+)/version/[^/]+$}.freeze
77

8+
extend self
89
extend PactBroker::Repositories
10+
extend PactBroker::Services
911

1012
def find params
1113
matrix_repository.find params[:consumer_name], params[:provider_name]
@@ -14,6 +16,35 @@ def find params
1416
def find_compatible_pacticipant_versions criteria
1517
matrix_repository.find_compatible_pacticipant_versions criteria
1618
end
19+
20+
def validate_selectors selectors
21+
error_messages = []
22+
selectors.each do | version_selector |
23+
if !(version_selector =~ VERSION_SELECTOR_PATTERN)
24+
error_messages << "Invalid version selector '#{version_selector}'. Format must be <pacticipant_name>/version/<version>"
25+
end
26+
end
27+
28+
selectors.each do | version_selector |
29+
if match = version_selector.match(VERSION_SELECTOR_PATTERN)
30+
pacticipant_name = match[1]
31+
unless pacticipant_service.find_pacticipant_by_name(pacticipant_name)
32+
error_messages << "Pacticipant '#{pacticipant_name}' not found"
33+
end
34+
end
35+
end
36+
37+
if error_messages.empty?
38+
selected_versions = version_service.find_versions_by_selector(selectors)
39+
if selected_versions.any?(&:nil?)
40+
selected_versions.each_with_index do | selected_version, i |
41+
error_messages << "No pact or verification found for #{selectors[i]}"
42+
end
43+
end
44+
end
45+
46+
error_messages
47+
end
1748
end
1849
end
1950
end

spec/features/get_matrix_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
let(:path) { "/matrix" }
1111
let(:params) do
1212
{
13-
selector: ['Consumer/version/1.0.0','Provider/version/4.5.6']
13+
selectors: ['Consumer/version/1.0.0','Provider/version/4.5.6']
1414
}
1515
end
1616
let(:last_response_body) { JSON.parse(subject.body, symbolize_names: true) }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
require 'pact_broker/api/resources/matrix'
2+
require 'pact_broker/matrix/service'
3+
4+
module PactBroker
5+
module Api
6+
module Resources
7+
describe Matrix do
8+
before do
9+
allow(PactBroker::Matrix::Service).to receive(:validate_selectors).and_return(error_messages)
10+
end
11+
12+
let(:td) { TestDataBuilder.new }
13+
let(:path) { "/matrix" }
14+
let(:json_response_body) { JSON.parse(subject.body, symbolize_names: true) }
15+
let(:params) { { selectors: ['Foo/version/1', 'Bar/version/2'] } }
16+
let(:error_messages) { [] }
17+
18+
subject { get path, params, {'Content-Type' => 'application/hal+json'}; last_response }
19+
20+
it "validates the selectors" do
21+
expect(PactBroker::Matrix::Service).to receive(:validate_selectors).with(['Foo/version/1', 'Bar/version/2'])
22+
subject
23+
end
24+
25+
context "when a validation error occurs" do
26+
let(:error_messages) { ['foo'] }
27+
it "returns a 400 status" do
28+
expect(subject.status).to eq 400
29+
end
30+
31+
it "returns error messages" do
32+
expect(json_response_body[:errors]).to eq ['foo']
33+
end
34+
end
35+
end
36+
end
37+
end
38+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
require 'pact_broker/matrix/service'
2+
3+
module PactBroker
4+
module Matrix
5+
describe Service do
6+
describe "validate_selectors" do
7+
let(:td) { TestDataBuilder.new }
8+
9+
subject { Service.validate_selectors(selectors) }
10+
11+
context "when a selector format is invalid" do
12+
let(:selectors) { ["Foo/1"] }
13+
14+
it "returns error messages" do
15+
expect(subject.first).to eq "Invalid version selector 'Foo/1'. Format must be <pacticipant_name>/version/<version>"
16+
end
17+
end
18+
19+
context "when one or more of the selectors does not match any known version" do
20+
before do
21+
td.create_pacticipant("Foo")
22+
end
23+
24+
let(:selectors) { ["Foo/version/1"] }
25+
26+
it "returns error messages" do
27+
expect(subject.first).to eq "No pact or verification found for Foo/version/1"
28+
end
29+
end
30+
31+
context "when the pacticipant does not exist" do
32+
let(:selectors) { ["Foo/version/1"] }
33+
34+
it "returns error messages" do
35+
expect(subject.first).to eq "Pacticipant 'Foo' not found"
36+
end
37+
end
38+
end
39+
end
40+
end
41+
end
42+

spec/migrations/44_add_provider_version_to_verification_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242

4343
it "sets the created_at date of the new version to the created_at of the verification" do
4444
subject
45-
expect(PactBroker::Domain::Verification.first.provider_version.created_at).to eq now
45+
expect(PactBroker::Domain::Verification.first.provider_version.created_at.to_datetime).to eq now
4646
end
4747

4848
context "when the version already exists" do

spec/service_consumers/provider_states_for_pact_broker_client.rb

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
Pact.provider_states_for "Pact Broker Client" do
44

5+
provider_state "the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6" do
6+
set_up do
7+
TestDataBuilder.new
8+
.create_pact_with_hierarchy("Foo", "1.2.3", "Bar")
9+
.create_verification(provider_version: "4.5.6")
10+
.create_verification(provider_version: "7.8.9", number: 2)
11+
.create_consumer_version("2.0.0")
12+
.create_pact
13+
.create_verification(provider_version: "4.5.6")
14+
end
15+
end
16+
517
provider_state "the 'Pricing Service' does not exist in the pact-broker" do
618
no_op
719
end

0 commit comments

Comments
 (0)