From: Michal Fojtik <mfoj...@redhat.com> * Wrong attribute values are not reported correctly
Signed-off-by: Michal fojtik <mfoj...@redhat.com> --- server/lib/cimi/models/resource.rb | 5 ++ server/lib/cimi/models/schema.rb | 88 +++++++++++++++++--- server/tests/cimi/model/errors_spec.rb | 141 +++++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+), 9 deletions(-) create mode 100644 server/tests/cimi/model/errors_spec.rb diff --git a/server/lib/cimi/models/resource.rb b/server/lib/cimi/models/resource.rb index 9f5bb66..2b3de42 100644 --- a/server/lib/cimi/models/resource.rb +++ b/server/lib/cimi/models/resource.rb @@ -36,6 +36,11 @@ module CIMI # def initialize(values = {}) names = self.class.schema.attribute_names + unless values.is_a?(::Hash) or values.kind_of?(CIMI::Model::Resource) + raise CIMI::Model::Schema::InvalidAttributeValue.new( + "The #{self.class} must be initialized using Hash or CIMI::Resource (is #{values.inspect})" + ) + end @select_attrs = values[:select_attr_list] || [] # Make sure we always have the :id of the entity even # the $select parameter is used and :id is filtered out diff --git a/server/lib/cimi/models/schema.rb b/server/lib/cimi/models/schema.rb index 5a2049b..3a9d54c 100644 --- a/server/lib/cimi/models/schema.rb +++ b/server/lib/cimi/models/schema.rb @@ -19,6 +19,8 @@ require_relative "../../deltacloud/core_ext" # The smarts of converting from XML and JSON into internal objects class CIMI::Model::Schema + class InvalidAttributeValue < StandardError; end + # # Attributes describe how we extract values from XML/JSON # @@ -60,6 +62,12 @@ class CIMI::Model::Schema def valid?(value) !value.nil? and !value.to_s.empty? end + + def report_error(message) + message = "The `#{@name}` attribute #{message}" + raise CIMI::Model::Schema::InvalidAttributeValue.new(message) + end + end class Scalar < Attribute @@ -190,6 +198,7 @@ class CIMI::Model::Schema @klass = CIMI::Model::const_get(refname) else @klass = Class.new(opts[:class]) do |m| + def initialize(values={}); super(values); end scalar :href end CIMI::Model::const_set(refname, @klass) @@ -207,6 +216,39 @@ class CIMI::Model::Schema a.valid?(value.send(a.name)) } end + + def to_xml(model, xml) + super if valid_ref?(model[name]) + end + + def to_json(model, json) + super if valid_ref?(model[name]) + end + + private + + def valid_ref?(value) + return true if value.is_a?(::Hash) or value.kind_of?(CIMI::Model::Resource) or value.nil? + report_error "must be a Hash or CIMI::Resource (is #{value})" + end + end + + class Href < CIMI::Model::Schema::Struct + + def to_xml(model, xml) + super if valid_href?(model[name]) + end + + def to_json(model, json) + super if valid_href?(model[name]) + end + + private + + def valid_href?(value) + return true if value.is_a?(::Hash) or value.is_a?(struct) or value.nil? + report_error "must be a Hash{:href} or Struct#href (is #{value})" + end end class Array < Attribute @@ -239,13 +281,25 @@ class CIMI::Model::Schema end def to_xml(model, xml) - ary = (model[name] || []).map { |elt| @struct.convert_to_xml(elt) } - xml[xml_name] = ary unless ary.empty? + return unless model[name] + if is_valid_array? model[name] + ary = model[name].map { |elt| @struct.convert_to_xml(elt) } + xml[xml_name] = ary unless ary.empty? + end end def to_json(model, json) - ary = (model[name] || []).map { |elt| @struct.convert_to_json(elt) } - json[json_name] = ary unless ary.empty? + return unless model[name] + if is_valid_array? model[name] + ary = model[name].map { |elt| @struct.convert_to_json(elt) } + json[json_name] = ary unless ary.empty? + end + end + + private + + def is_valid_array?(value) + value.is_a?(::Array) ? true : report_error('must be a valid Array') end end @@ -268,15 +322,26 @@ class CIMI::Model::Schema end def to_xml(model, xml) - ary = (model[name] || {}).map { |k, v| { "key" => k, "content" => v } } - xml[xml_name] = ary unless ary.empty? + return unless model[name] + if is_valid_hash? model[name] + ary = (model[name]).map { |k, v| { "key" => k, "content" => v } } + xml[xml_name] = ary unless ary.empty? + end end def to_json(model, json) - if model[name] && ! model[name].empty? - json[json_name] = model[name] + return unless model[name] + if is_valid_hash? model[name] + json[json_name] = model[name] unless model[name].empty? end end + + private + + def is_valid_hash?(value) + value.is_a?(::Hash) ? true : report_error('must be a valid Hash') + end + end class Collection < Attribute @@ -413,7 +478,12 @@ class CIMI::Model::Schema def href(*args) opts = args.extract_opts! - args.each { |arg| struct(arg, opts) { scalar :href, :required => opts[:required] } } + #args.each { |arg| struct(arg, opts) { scalar :href, :required => opts[:required] } } + args.each { |arg| + add_attributes!([arg, opts], Href) { + scalar :href, :required => opts[:required] + } + } end def text(*args) diff --git a/server/tests/cimi/model/errors_spec.rb b/server/tests/cimi/model/errors_spec.rb new file mode 100644 index 0000000..fac38fb --- /dev/null +++ b/server/tests/cimi/model/errors_spec.rb @@ -0,0 +1,141 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +require 'rubygems' +require 'require_relative' if RUBY_VERSION < '1.9' + +require_relative '../spec_helper.rb' if require 'minitest/autorun' + +describe 'Schema' do + describe 'Hash attributes' do + + it 'should not report error when attribute is set properly' do + machine = CIMI::Model::MachineTemplate.new(:property => {}) + machine.to_xml.must_be_kind_of String + machine.to_json.must_be_kind_of String + end + + it 'should not report error when attribute is nil' do + machine = CIMI::Model::MachineTemplate.new(:property => nil) + machine.to_xml.must_be_kind_of String + machine.to_json.must_be_kind_of String + end + + it 'should not report error when attribute is not set' do + machine = CIMI::Model::MachineTemplate.new + machine.to_xml.must_be_kind_of String + machine.to_json.must_be_kind_of String + end + + it 'should report invalid value for Hash attribute when set to String' do + machine = CIMI::Model::MachineTemplate.new(:property => '') + lambda { machine.to_xml }.must_raise CIMI::Model::Schema::InvalidAttributeValue + lambda { machine.to_json }.must_raise CIMI::Model::Schema::InvalidAttributeValue + end + + it 'should report invalid value for Hash attribute when set to Array' do + machine = CIMI::Model::MachineTemplate.new(:property => []) + lambda { machine.to_xml }.must_raise CIMI::Model::Schema::InvalidAttributeValue + lambda { machine.to_json }.must_raise CIMI::Model::Schema::InvalidAttributeValue + end + + end + + describe 'Array attributes' do + + it 'should report invalid value when set to Hash' do + machine = CIMI::Model::MachineTemplate.new(:volumes => {} ) + lambda { machine.to_xml }.must_raise CIMI::Model::Schema::InvalidAttributeValue + lambda { machine.to_json }.must_raise CIMI::Model::Schema::InvalidAttributeValue + end + + it 'should report invalid value when set to String' do + machine = CIMI::Model::MachineTemplate.new(:volumes => '' ) + lambda { machine.to_xml }.must_raise CIMI::Model::Schema::InvalidAttributeValue + lambda { machine.to_json }.must_raise CIMI::Model::Schema::InvalidAttributeValue + end + + it 'should not report error when attribute is set properly' do + machine = CIMI::Model::MachineTemplate.new(:volumes => []) + machine.to_xml.must_be_kind_of String + machine.to_json.must_be_kind_of String + end + + it 'should not report error when attribute is nil' do + machine = CIMI::Model::MachineTemplate.new(:volumes => nil) + machine.to_xml.must_be_kind_of String + machine.to_json.must_be_kind_of String + + end + + it 'should not report error when attribute is not set' do + machine = CIMI::Model::MachineTemplate.new + machine.to_xml.must_be_kind_of String + machine.to_json.must_be_kind_of String + end + end + + describe 'Ref attributes' do + + it 'should report error when initialized using Array' do + lambda { + CIMI::Model::MachineTemplate.new(:machine_config => []) + }.must_raise CIMI::Model::Schema::InvalidAttributeValue + end + + it 'should report error when initialized using String' do + lambda { + CIMI::Model::MachineTemplate.new(:machine_config => '') + }.must_raise CIMI::Model::Schema::InvalidAttributeValue + end + + it 'could be initialized by the Hash value' do + machine = CIMI::Model::MachineTemplate.new(:machine_config => { :href => 'http://localhost/1' }) + machine.machine_config.must_be_instance_of CIMI::Model::MachineConfigurationRef + machine.machine_config.href.must_equal 'http://localhost/1' + machine.to_xml.must_be_instance_of String + machine.to_json.must_be_instance_of String + end + + it 'could be initialized by the Ref value' do + machine = CIMI::Model::MachineTemplate.new(:machine_config => CIMI::Model::MachineConfigurationRef.new(:href => 'http://localhost/1')) + machine.machine_config.must_be_instance_of CIMI::Model::MachineConfigurationRef + machine.machine_config.href.must_equal 'http://localhost/1' + machine.to_xml.must_be_instance_of String + machine.to_json.must_be_instance_of String + end + + end + + describe 'Href attributes' do + + it 'should report error when value is not a Hash' do + machine = CIMI::Model::Machine.new(:machine_image => '') + lambda { + machine.to_xml + }.must_raise CIMI::Model::Schema::InvalidAttributeValue + lambda { + machine.to_json + }.must_raise CIMI::Model::Schema::InvalidAttributeValue + end + + it 'should not report error when initialized correctly' do + machine = CIMI::Model::Machine.new( :machine_image => { :href => 'test' }) + machine.to_xml.must_be_instance_of String + machine.to_json.must_be_instance_of String + end + end + +end -- 1.8.1.4