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

Reply via email to