diff --git a/lib/pact_broker/api/contracts/publish_contracts_contract_contract.rb b/lib/pact_broker/api/contracts/publish_contracts_contract_contract.rb index 8196c2bca..550cf6667 100644 --- a/lib/pact_broker/api/contracts/publish_contracts_contract_contract.rb +++ b/lib/pact_broker/api/contracts/publish_contracts_contract_contract.rb @@ -20,23 +20,7 @@ class PublishContractsContractContract < BaseContract rule(:consumerName).validate(:not_blank_if_present) rule(:providerName).validate(:not_blank_if_present) - # validate_consumer_name_in_content - rule(:decodedParsedContent, :consumerName, :specification) do - consumer_name_in_content = values.dig(:decodedParsedContent, :consumer, :name) - if consumer_name_in_content && consumer_name_in_content != values[:consumerName] - base.failure(validation_message("consumer_name_in_content_mismatch", { consumer_name_in_content: consumer_name_in_content, consumer_name: values[:consumerName] })) - end - end - - # validate_provider_name_in_content - rule(:decodedParsedContent, :providerName) do - provider_name_in_content = values.dig(:decodedParsedContent, :provider, :name) - if provider_name_in_content && provider_name_in_content != values[:providerName] - base.failure(validation_message("provider_name_in_content_mismatch", { provider_name_in_content: provider_name_in_content, provider_name: values[:providerName] })) - end - end - - # validate_encoding + # validate_encoding (ensure all UTF-8 chars) rule(:decodedContent) do if value.nil? base.failure(validation_message("base64")) @@ -50,12 +34,39 @@ class PublishContractsContractContract < BaseContract end end - # validate_content_matches_content_type + # validate content could be parsed according to its content type rule(:decodedParsedContent, :contentType) do if values[:decodedParsedContent].nil? && values[:contentType] base.failure(validation_message("invalid_content_for_content_type", { content_type: values[:contentType] })) end end + + # validate parsed contract is a hash + rule(:decodedParsedContent, :contentType) do + if !base_rule_error? && !values[:decodedParsedContent].is_a?(Hash) + base.failure(validation_message("invalid_parsed_contract_class", { actual_class: values[:decodedParsedContent].class })) + end + end + + # validate consumer name in content matches the details higher in the JSON document + rule(:decodedParsedContent, :consumerName, :specification) do + if !base_rule_error? + consumer_name_in_content = values.dig(:decodedParsedContent, :consumer, :name) + if consumer_name_in_content && consumer_name_in_content != values[:consumerName] + base.failure(validation_message("consumer_name_in_content_mismatch", { consumer_name_in_content: consumer_name_in_content, consumer_name: values[:consumerName] })) + end + end + end + + # validate provider name in content matches the details higher in the JSON document + rule(:decodedParsedContent, :providerName) do + if !base_rule_error? + provider_name_in_content = values.dig(:decodedParsedContent, :provider, :name) + if provider_name_in_content && provider_name_in_content != values[:providerName] + base.failure(validation_message("provider_name_in_content_mismatch", { provider_name_in_content: provider_name_in_content, provider_name: values[:providerName] })) + end + end + end end end end diff --git a/lib/pact_broker/locale/en.yml b/lib/pact_broker/locale/en.yml index 5c4b4c324..142929fe3 100644 --- a/lib/pact_broker/locale/en.yml +++ b/lib/pact_broker/locale/en.yml @@ -89,6 +89,7 @@ en: environment_with_name_not_found: "Environment with name '%{name}' does not exist" cannot_modify_version_branch: "The branch for a pacticipant version cannot be changed once set (currently '%{old_branch}', proposed value '%{new_branch}'). Your pact publication/verification publication configurations may be in conflict with each other if you are seeing this error. If the current branch value is incorrect, you must delete the pacticipant version resource at %{version_url} and publish the pacts/verification results again with a consistent branch name." invalid_content_for_content_type: "content could not be parsed as %{content_type}" + invalid_parsed_contract_class: "parsed content was expected to be a Hash but was a %{actual_class}" cannot_set_currently_deployed_true: The currentlyDeployed property cannot be set back to true. Please record a new deployment. cannot_set_currently_supported_true: The currentlySupported property cannot be set back to true. Please record a new deployment. invalid_limit: The limit must be 1 or greater. diff --git a/spec/lib/pact_broker/api/contracts/publish_contracts_schema_spec.rb b/spec/lib/pact_broker/api/contracts/publish_contracts_schema_spec.rb index decc5fd24..b296e7343 100644 --- a/spec/lib/pact_broker/api/contracts/publish_contracts_schema_spec.rb +++ b/spec/lib/pact_broker/api/contracts/publish_contracts_schema_spec.rb @@ -125,6 +125,12 @@ module Contracts its([:contracts, 0]) { is_expected.to include "blank" } end + context "when the contract has been successfully JSON parsed to an object that is not a hash" do + let(:decoded_parsed_content) { "contract" } + + its([:contracts, 0]) { is_expected.to eq "parsed content was expected to be a Hash but was a String (at index 0)" } + end + context "when the consumer name is missing and there is a validation error with the content" do let(:params) do JSON.parse(File.read("spec/fixtures/invalid-publish-contract-body.json"), symbolize_names: true)