Improve logging when validation fails

Add guid and author to error messages if available.
This commit is contained in:
Benjamin Neff 2017-06-11 15:50:01 +02:00
parent d901ceb500
commit c0ea38d258
No known key found for this signature in database
GPG key ID: 971464C3F1A90194
6 changed files with 113 additions and 21 deletions

View file

@ -187,15 +187,21 @@ module DiasporaFederation
type = data.fetch(:parent_type) {
break self::PARENT_TYPE if const_defined?(:PARENT_TYPE)
raise DiasporaFederation::Entity::ValidationError, "invalid #{self}! missing 'parent_type'."
raise DiasporaFederation::Entity::ValidationError, error_message_missing_property(data, "parent_type")
}
guid = data.fetch(:parent_guid) {
raise DiasporaFederation::Entity::ValidationError, "invalid #{self}! missing 'parent_guid'."
raise DiasporaFederation::Entity::ValidationError, error_message_missing_property(data, "parent_guid")
}
data[:parent] = RelatedEntity.fetch(data[:author], type, guid)
end
def error_message_missing_property(data, missing_property)
obj_str = "#{class_name}#{":#{data[:guid]}" if data.has_key?(:guid)}" \
"#{" from #{data[:author]}" if data.has_key?(:author)}"
"Invalid #{obj_str}! Missing '#{missing_property}'."
end
def xml_parser_class
DiasporaFederation::Parsers::RelayableXmlParser
end

View file

@ -131,7 +131,7 @@ module DiasporaFederation
#
# @return [String] entity name
def self.entity_name
name.rpartition("::").last.tap do |word|
class_name.tap do |word|
word.gsub!(/(.)([A-Z])/, '\1_\2')
word.downcase!
end
@ -154,9 +154,14 @@ module DiasporaFederation
Entities.const_get(class_name)
end
# @return [String] class name as string
def self.class_name
name.rpartition("::").last
end
# @return [String] string representation of this object
def to_s
"#{self.class.name.rpartition('::').last}#{":#{guid}" if respond_to?(:guid)}"
"#{self.class.class_name}#{":#{guid}" if respond_to?(:guid)}"
end
# Renders entity to a hash representation of the entity JSON format
@ -190,7 +195,11 @@ module DiasporaFederation
def validate_missing_props(entity_data)
missing_props = self.class.missing_props(entity_data)
raise ValidationError, "missing required properties: #{missing_props.join(', ')}" unless missing_props.empty?
return if missing_props.empty?
obj_str = "#{self.class.class_name}#{":#{entity_data[:guid]}" if entity_data.has_key?(:guid)}" \
"#{" from #{entity_data[:author]}" if entity_data.has_key?(:author)}"
raise ValidationError, "#{obj_str}: Missing required properties: #{missing_props.join(', ')}"
end
def setable?(name, val)
@ -246,7 +255,7 @@ module DiasporaFederation
errors = validator.errors.map do |prop, rule|
"property: #{prop}, value: #{public_send(prop).inspect}, rule: #{rule[:rule]}, with params: #{rule[:params]}"
end
"Failed validation for properties: #{errors.join(' | ')}"
"Failed validation for #{self}#{" from #{author}" if respond_to?(:author)} for properties: #{errors.join(' | ')}"
end
# @return [Hash] hash with all properties

View file

@ -57,6 +57,12 @@ module DiasporaFederation
entity :multi, [OtherEntity]
end
class TestEntityWithAuthorAndGuid < DiasporaFederation::Entity
property :test, :string
property :author, :string
property :guid, :string
end
class SomeRelayable < DiasporaFederation::Entity
PARENT_TYPE = "Parent".freeze
@ -74,5 +80,13 @@ module DiasporaFederation
rule :test2, :not_nil
rule :test3, :boolean
end
class TestEntityWithAuthorAndGuidValidator < Validation::Validator
include Validation
rule :test, :boolean
rule :author, %i(not_empty diaspora_id)
rule :guid, :guid
end
end
end

View file

@ -62,28 +62,24 @@ JSON
broken_xml = <<-XML
<like>
<parent_guid>#{parent.guid}</parent_guid>
<author_signature>#{data[:author_signature]}</author_signature>
<parent_author_signature>#{data[:parent_author_signature]}</parent_author_signature>
</like>
XML
expect {
DiasporaFederation::Entities::Like.from_xml(Nokogiri::XML(broken_xml).root)
}.to raise_error Entity::ValidationError, "invalid DiasporaFederation::Entities::Like! missing 'parent_type'."
}.to raise_error Entity::ValidationError, "Invalid Like! Missing 'parent_type'."
end
it "raises a ValidationError if the parent_guid is missing" do
broken_xml = <<-XML
<like>
<target_type>#{parent.entity_type}</target_type>
<author_signature>#{data[:author_signature]}</author_signature>
<parent_author_signature>#{data[:parent_author_signature]}</parent_author_signature>
</like>
XML
expect {
DiasporaFederation::Entities::Like.from_xml(Nokogiri::XML(broken_xml).root)
}.to raise_error Entity::ValidationError, "invalid DiasporaFederation::Entities::Like! missing 'parent_guid'."
}.to raise_error Entity::ValidationError, "Invalid Like! Missing 'parent_guid'."
end
end
end

View file

@ -256,15 +256,36 @@ XML
it "raises a ValidationError if the parent_guid is missing" do
broken_xml = <<-XML
<some_relayable>
<author_signature/>
<parent_author_signature/>
</some_relayable>
XML
expect {
Entities::SomeRelayable.from_xml(Nokogiri::XML(broken_xml).root)
}.to raise_error Entity::ValidationError,
"invalid DiasporaFederation::Entities::SomeRelayable! missing 'parent_guid'."
}.to raise_error Entity::ValidationError, "Invalid SomeRelayable! Missing 'parent_guid'."
end
it "adds the guid to the error message if available" do
broken_xml = <<-XML
<some_relayable>
<guid>#{guid}</guid>
</some_relayable>
XML
expect {
Entities::SomeRelayable.from_xml(Nokogiri::XML(broken_xml).root)
}.to raise_error Entity::ValidationError, "Invalid SomeRelayable:#{guid}! Missing 'parent_guid'."
end
it "adds the author to the error message if available" do
broken_xml = <<-XML
<some_relayable>
<author>#{author}</author>
</some_relayable>
XML
expect {
Entities::SomeRelayable.from_xml(Nokogiri::XML(broken_xml).root)
}.to raise_error Entity::ValidationError, "Invalid SomeRelayable from #{author}! Missing 'parent_guid'."
end
end
end

View file

@ -1,6 +1,7 @@
module DiasporaFederation
describe Entity do
let(:data) { {test1: "asdf", test2: 1234, test3: false, test4: false} }
let(:guid) { Fabricate.sequence(:guid) }
it "should extend Entity" do
expect(Entities::TestDefaultEntity).to be < Entity
@ -12,10 +13,26 @@ module DiasporaFederation
expect(entity).to be_frozen
end
it "checks for required properties" do
expect {
Entities::TestDefaultEntity.new({})
}.to raise_error Entity::ValidationError, "missing required properties: test1, test2"
context "required properties" do
it "checks for required properties" do
expect {
Entities::TestDefaultEntity.new({})
}.to raise_error Entity::ValidationError, "TestDefaultEntity: Missing required properties: test1, test2"
end
it "adds the guid to the error message if available" do
expect {
Entities::TestDefaultEntity.new(guid: guid)
}.to raise_error Entity::ValidationError,
"TestDefaultEntity:#{guid}: Missing required properties: test1, test2"
end
it "adds the author to the error message if available" do
expect {
Entities::TestDefaultEntity.new(author: alice.diaspora_id)
}.to raise_error Entity::ValidationError,
"TestDefaultEntity from #{alice.diaspora_id}: Missing required properties: test1, test2"
end
end
context "defaults" do
@ -48,7 +65,8 @@ module DiasporaFederation
it "validates the entity and raise an error with failed properties if not valid" do
expect {
Entities::TestDefaultEntity.new(invalid_data)
}.to raise_error Entity::ValidationError, /Failed validation for properties:.*test1.*\|.*test2.*\|.*test3/
}.to raise_error Entity::ValidationError,
/Failed validation for TestDefaultEntity for properties:.*test1.*\|.*test2.*\|.*test3/
end
it "contains the failed rule" do
@ -62,6 +80,34 @@ module DiasporaFederation
Entities::TestDefaultEntity.new(invalid_data)
}.to raise_error Entity::ValidationError, /rule: regular_expression, with params: \{:regex=>.*\}/
end
it "adds the guid to the error message if available" do
expect {
Entities::TestEntityWithAuthorAndGuid.new(test: "invalid", guid: guid, author: alice.diaspora_id)
}.to raise_error Entity::ValidationError,
/Failed validation for TestEntityWithAuthorAndGuid:#{guid} from .* for properties:.*/
end
it "handles missing guid" do
expect {
Entities::TestEntityWithAuthorAndGuid.new(test: "invalid", guid: nil, author: alice.diaspora_id)
}.to raise_error Entity::ValidationError,
/Failed validation for TestEntityWithAuthorAndGuid: from .* for properties:.*/
end
it "adds the author to the error message if available" do
expect {
Entities::TestEntityWithAuthorAndGuid.new(test: "invalid", guid: guid, author: alice.diaspora_id)
}.to raise_error Entity::ValidationError,
/Failed validation for .* from #{alice.diaspora_id} for properties:.*/
end
it "handles missing author" do
expect {
Entities::TestEntityWithAuthorAndGuid.new(test: "invalid", guid: guid, author: nil)
}.to raise_error Entity::ValidationError,
/Failed validation for .* from for properties:.*/
end
end
end