diff --git a/lib/pact_broker/api/resources/matrix.rb b/lib/pact_broker/api/resources/matrix.rb index ca0c48c49..f82522ea0 100644 --- a/lib/pact_broker/api/resources/matrix.rb +++ b/lib/pact_broker/api/resources/matrix.rb @@ -1,6 +1,6 @@ require 'pact_broker/api/resources/base_resource' require 'pact_broker/api/decorators/matrix_decorator' -require 'cgi' +require 'pact_broker/matrix/parse_query' module PactBroker module Api @@ -16,7 +16,7 @@ def allowed_methods end def malformed_request? - error_messages = matrix_service.validate_selectors(selectors) + error_messages = matrix_service.validate_selectors(criteria) if error_messages.any? set_json_validation_error_messages error_messages true @@ -26,21 +26,12 @@ def malformed_request? end def to_json - criteria = selected_versions.each_with_object({}) { | version, hash | hash[version.pacticipant.name] = version.number } lines = matrix_service.find(criteria) PactBroker::Api::Decorators::MatrixPactDecorator.new(lines).to_json(user_options: { base_url: base_url }) end - def selectors - @selectors ||= CGI.parse(CGI.unescape(request.uri.query))['selectors[]'] - end - - def version_selectors - @version_selectors ||= selectors.select{ | selector| selector.include?("/version/") } - end - - def selected_versions - @selected_versions ||= version_service.find_versions_by_selector(version_selectors) + def criteria + @criteria ||= PactBroker::Matrix::ParseQuery.call(request.uri.query) end end end diff --git a/lib/pact_broker/matrix/parse_query.rb b/lib/pact_broker/matrix/parse_query.rb new file mode 100644 index 000000000..8992f92a1 --- /dev/null +++ b/lib/pact_broker/matrix/parse_query.rb @@ -0,0 +1,14 @@ +require 'cgi' + +module PactBroker + module Matrix + class ParseQuery + def self.call query + params = CGI.parse(CGI.unescape(query)) + params['pacticipant[]'].zip(params['version[]']).each_with_object({}) do | (pacticipant, version), hash | + hash[pacticipant] = version + end + end + end + end +end diff --git a/lib/pact_broker/matrix/service.rb b/lib/pact_broker/matrix/service.rb index f95dab487..9d4364ec6 100644 --- a/lib/pact_broker/matrix/service.rb +++ b/lib/pact_broker/matrix/service.rb @@ -3,7 +3,6 @@ module PactBroker module Matrix module Service - VERSION_SELECTOR_PATTERN = %r{(^[^/]+)/version/[^/]+$}.freeze extend self extend PactBroker::Repositories @@ -23,27 +22,17 @@ def find_compatible_pacticipant_versions criteria def validate_selectors selectors error_messages = [] - selectors.each do | version_selector | - if !(version_selector =~ VERSION_SELECTOR_PATTERN) - error_messages << "Invalid version selector '#{version_selector}'. Format must be /version/" - end - end - selectors.each do | version_selector | - if match = version_selector.match(VERSION_SELECTOR_PATTERN) - pacticipant_name = match[1] - unless pacticipant_service.find_pacticipant_by_name(pacticipant_name) - error_messages << "Pacticipant '#{pacticipant_name}' not found" - end + selectors.keys.each do | pacticipant_name | + unless pacticipant_service.find_pacticipant_by_name(pacticipant_name) + error_messages << "Pacticipant '#{pacticipant_name}' not found" end end if error_messages.empty? - selected_versions = version_service.find_versions_by_selector(selectors) - if selected_versions.any?(&:nil?) - selected_versions.each_with_index do | selected_version, i | - error_messages << "No pact or verification found for #{selectors[i]}" if selected_version.nil? - end + selectors.each do | pacticipant_name, version_number | + version = version_service.find_by_pacticipant_name_and_number(pacticipant_name: pacticipant_name, pacticipant_version_number: version_number) + error_messages << "No pact or verification found for #{pacticipant_name} version #{version_number}" if version.nil? end end diff --git a/script/seed-matrix.rb b/script/seed-matrix.rb new file mode 100755 index 000000000..1da8cfe96 --- /dev/null +++ b/script/seed-matrix.rb @@ -0,0 +1,71 @@ +#!/usr/bin/env ruby + +raise "Please supply database path" unless ARGV[0] + +$LOAD_PATH.unshift './lib' +$LOAD_PATH.unshift './spec' +ENV['RACK_ENV'] = 'development' +require 'sequel' +require 'logger' +DATABASE_CREDENTIALS = {logger: Logger.new($stdout), adapter: "sqlite", database: ARGV[0], :encoding => 'utf8'} +connection = Sequel.connect(DATABASE_CREDENTIALS) +connection.timezone = :utc +require 'pact_broker/db' +PactBroker::DB.connection = connection +require 'pact_broker' +require 'support/test_data_builder' + + +tables_to_clean = [:labels, :webhook_executions, :triggered_webhooks, :verifications, :pact_publications, :pact_versions, :pacts, :pact_version_contents, :tags, :versions, :webhook_headers, :webhooks, :pacticipants] + +tables_to_clean.each do | table_name | + connection[table_name].delete if connection.table_exists?(table_name) +end + +=begin + +A -> B -> C + +1 s 1 f 1 + + 2 s 2 + +=end + +# TestDataBuilder.new.create_pact_with_hierarchy("A", "1.2.3", "B") +# .use_provider("B") +# .create_version("2.0.0") +# .create_provider("C") +# .create_version("3.0.0") +# .create_pact + +TestDataBuilder.new + .create_pact_with_hierarchy("A", "1", "B") + .create_verification(provider_version: '1') + .create_verification(provider_version: '2', number: 2, success: false) + .create_verification(provider_version: '4', number: 3) + .create_provider_version("5") + .use_consumer("B") + .use_consumer_version("1") + .create_provider("C") + .create_pact + .create_verification(provider_version: '1', success: false) + .use_consumer_version("2") + .create_pact + .create_verification(provider_version: '2', success: true) + .create_consumer_version("3") + .create_pact + .create_pact_with_hierarchy("the-example-application", "391c43cae8c0e83c570c191f7324fccd67e53abc", "another-example-application") + .create_verification(provider_version: '391c43cae8c0e83c570c191f7324fccd67e53abc') + .create_verification(provider_version: '57fa24e44efc4d8aa42bb855a8217f145b5b1b5b', number: 2, success: false) + .create_verification(provider_version: '4', number: 3) + .use_consumer("another-example-application") + .use_consumer_version("391c43cae8c0e83c570c191f7324fccd67e53abc") + .create_provider("a-third-example-application") + .create_pact + .create_verification(provider_version: '391c43cae8c0e83c570c191f7324fccd67e53abc', success: false) + .use_consumer_version("57fa24e44efc4d8aa42bb855a8217f145b5b1b5b") + .create_pact + .create_verification(provider_version: '57fa24e44efc4d8aa42bb855a8217f145b5b1b5b', success: true) + + diff --git a/spec/features/get_matrix_spec.rb b/spec/features/get_matrix_spec.rb index a4e140e10..8d430aa72 100644 --- a/spec/features/get_matrix_spec.rb +++ b/spec/features/get_matrix_spec.rb @@ -10,7 +10,8 @@ let(:path) { "/matrix" } let(:params) do { - selectors: ['Consumer/version/1.0.0','Provider/version/4.5.6'] + pacticipant: ['Consumer', 'Provider'], + version: ['1.0.0', '4.5.6'] } end let(:last_response_body) { JSON.parse(subject.body, symbolize_names: true) } diff --git a/spec/lib/pact_broker/api/resources/matrix_spec.rb b/spec/lib/pact_broker/api/resources/matrix_spec.rb index 54d93f87c..13cb35e49 100644 --- a/spec/lib/pact_broker/api/resources/matrix_spec.rb +++ b/spec/lib/pact_broker/api/resources/matrix_spec.rb @@ -12,13 +12,13 @@ module Resources let(:td) { TestDataBuilder.new } let(:path) { "/matrix" } let(:json_response_body) { JSON.parse(subject.body, symbolize_names: true) } - let(:params) { { selectors: ['Foo/version/1', 'Bar/version/2'] } } + let(:params) { { pacticipant: ['Foo', 'Bar'], version: ['1', '2'] } } let(:error_messages) { [] } subject { get path, params, {'Content-Type' => 'application/hal+json'}; last_response } it "validates the selectors" do - expect(PactBroker::Matrix::Service).to receive(:validate_selectors).with(['Foo/version/1', 'Bar/version/2']) + expect(PactBroker::Matrix::Service).to receive(:validate_selectors).with('Foo' => '1', 'Bar' => '2') subject end diff --git a/spec/lib/pact_broker/matrix/parse_query_spec.rb b/spec/lib/pact_broker/matrix/parse_query_spec.rb new file mode 100644 index 000000000..a5039aafd --- /dev/null +++ b/spec/lib/pact_broker/matrix/parse_query_spec.rb @@ -0,0 +1,25 @@ +require 'pact_broker/matrix/parse_query' + +module PactBroker + module Matrix + describe ParseQuery do + describe ".call" do + let(:query) { "pacticipant[]=Foo&pacticipant[]=Bar&version[]=1.2.3&version[]=9.9.9" } + + subject { ParseQuery.call(query) } + + it "extracts the pacticipant names and respective versions" do + expect(subject).to eq "Foo" => "1.2.3", "Bar" => "9.9.9" + end + + context "with spaces" do + let(:query) { "pacticipant%5B%5D=Name%20With%20Spaces&version%5B%5D=1%202" } + + it "works" do + expect(subject).to eq "Name With Spaces" => "1 2" + end + end + end + end + end +end diff --git a/spec/lib/pact_broker/matrix/service_spec.rb b/spec/lib/pact_broker/matrix/service_spec.rb index 23bfa220e..5cf997361 100644 --- a/spec/lib/pact_broker/matrix/service_spec.rb +++ b/spec/lib/pact_broker/matrix/service_spec.rb @@ -9,13 +9,6 @@ module Matrix subject { Service.validate_selectors(selectors) } - context "when a selector format is invalid" do - let(:selectors) { ["Foo/1"] } - - it "returns error messages" do - expect(subject.first).to eq "Invalid version selector 'Foo/1'. Format must be /version/" - end - end context "when there is only one selector" do before do @@ -23,7 +16,7 @@ module Matrix .create_version("1") end - let(:selectors) { ["Foo/version/1"] } + let(:selectors) { {"Foo" => "1"} } it "returns error messages" do expect(subject.first).to eq "Please provide 2 or more version selectors." @@ -39,15 +32,15 @@ module Matrix end - let(:selectors) { ["Foo/version/1", "Bar/version/1"] } + let(:selectors) { {"Foo" => "1", "Bar" => "1"} } it "returns error messages" do - expect(subject).to eq ["No pact or verification found for Bar/version/1"] + expect(subject).to eq ["No pact or verification found for Bar version 1"] end end context "when the pacticipant does not exist" do - let(:selectors) { ["Foo/version/1"] } + let(:selectors) { {"Foo" => "1"} } it "returns error messages" do expect(subject.first).to eq "Pacticipant 'Foo' not found" diff --git a/spec/service_consumers/provider_states_for_pact_broker_client.rb b/spec/service_consumers/provider_states_for_pact_broker_client.rb index 57f9c51f6..b09fd0a58 100644 --- a/spec/service_consumers/provider_states_for_pact_broker_client.rb +++ b/spec/service_consumers/provider_states_for_pact_broker_client.rb @@ -2,6 +2,18 @@ Pact.provider_states_for "Pact Broker Client" do + provider_state "the pact for Foo Thing version 1.2.3 has been verified by Bar version 4.5.6" do + set_up do + TestDataBuilder.new + .create_pact_with_hierarchy("Foo Thing", "1.2.3", "Bar") + .create_verification(provider_version: "4.5.6") + .create_verification(provider_version: "7.8.9", number: 2) + .create_consumer_version("2.0.0") + .create_pact + .create_verification(provider_version: "4.5.6") + end + end + provider_state "the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6" do set_up do TestDataBuilder.new