You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by lu...@redhat.com on 2011/11/09 22:18:24 UTC

[PATCH 2/2] CIMI: model for machineTemplate

From: David Lutterkort <lu...@redhat.com>


Signed-off-by: David Lutterkort <lu...@redhat.com>
---
 server/lib/cimi/model/machine_template.rb       |   36 +++++++++
 server/spec/cimi/data/machine_template.json     |   30 ++++++++
 server/spec/cimi/data/machine_template.xml      |   24 ++++++
 server/spec/cimi/model/machine_template_spec.rb |   51 +++++++++++++
 server/spec/spec_helper.rb                      |   92 +++++++++++++++++++++++
 5 files changed, 233 insertions(+), 0 deletions(-)
 create mode 100644 server/lib/cimi/model/machine_template.rb
 create mode 100644 server/spec/cimi/data/machine_template.json
 create mode 100644 server/spec/cimi/data/machine_template.xml
 create mode 100644 server/spec/cimi/model/machine_template_spec.rb

diff --git a/server/lib/cimi/model/machine_template.rb b/server/lib/cimi/model/machine_template.rb
new file mode 100644
index 0000000..458f365
--- /dev/null
+++ b/server/lib/cimi/model/machine_template.rb
@@ -0,0 +1,36 @@
+# 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.
+
+class CIMI::Model::MachineTemplate < CIMI::Model::Base
+  href :machine_config
+  href :machine_image
+  href :machine_admin
+  array :volumes do
+    scalar :href
+    scalar :protocol
+    scalar :attachment_point
+  end
+  array :volume_templates do
+    scalar :href, :attachment_point, :protocol
+  end
+  array :network_interfaces do
+    href :vsp
+    text :hostname, :mac_address, :state, :protocol, :allocation
+    text :address, :default_gateway, :dns, :max_transmission_unit
+  end
+  array :operations do
+    scalar :rel, :href
+  end
+end
diff --git a/server/spec/cimi/data/machine_template.json b/server/spec/cimi/data/machine_template.json
new file mode 100644
index 0000000..54de58d
--- /dev/null
+++ b/server/spec/cimi/data/machine_template.json
@@ -0,0 +1,30 @@
+{
+  "uri": "http://cimi.example.org/machine_templates/1",
+  "name": "My First Template",
+  "description": "A template for testing",
+  "created": "2011-11-01",
+  "machineConfig": { "href": "http://cimi.example.org/machine_configs/1" },
+  "machineImage": { "href": "http://cimi.example.org/machine_images/1" },
+  "volumes": [{
+    "href": "http://cimi.example.org/volumes/1",
+    "attachmentPoint": "/dev/sda",
+    "protocol": "nfs"
+  }],
+  "networkInterfaces": [{
+    "vsp": { "href": "http://cimi.example.org/vsps/1" },
+    "hostname": "host.cimi.example.org",
+    "macAddress": "00:11:22:33:44:55",
+    "state": "UP",
+    "protocol": "TCP",
+    "allocation": "static",
+    "address": "192.168.0.17",
+    "defaultGateway": "192.168.0.1",
+    "dns": "192.168.0.1",
+    "maxTransmissionUnit": "1500"
+  }],
+  "operations": [
+    { "rel": "edit",
+      "href": "http://cimi.example.org/machine_templates/1/edit" },
+    { "rel": "delete",
+      "href": "http://cimi.example.org/machine_templates/1/delete" }]
+}
diff --git a/server/spec/cimi/data/machine_template.xml b/server/spec/cimi/data/machine_template.xml
new file mode 100644
index 0000000..160b311
--- /dev/null
+++ b/server/spec/cimi/data/machine_template.xml
@@ -0,0 +1,24 @@
+<MachineTemplate xmlns="http://www.dmtf.org/cimi">
+  <uri>http://cimi.example.org/machine_templates/1</uri>
+  <name>My First Template</name>
+  <description>A template for testing</description>
+  <created>2011-11-01</created>
+  <machineConfig href="http://cimi.example.org/machine_configs/1"/>
+  <machineImage href="http://cimi.example.org/machine_images/1"/>
+  <volume href="http://cimi.example.org/volumes/1"
+          attachmentPoint="/dev/sda" protocol="nfs" />
+  <networkInterface>
+    <vsp href="http://cimi.example.org/vsps/1"/>
+    <hostname>host.cimi.example.org</hostname>
+    <macAddress>00:11:22:33:44:55</macAddress>
+    <state>UP</state>
+    <protocol>TCP</protocol>
+    <allocation>static</allocation>
+    <address>192.168.0.17</address>
+    <defaultGateway>192.168.0.1</defaultGateway>
+    <dns>192.168.0.1</dns>
+    <maxTransmissionUnit>1500</maxTransmissionUnit>
+  </networkInterface>
+  <operation rel="edit" href="http://cimi.example.org/machine_templates/1/edit"/>
+  <operation rel="delete" href="http://cimi.example.org/machine_templates/1/delete"/>
+</MachineTemplate>
diff --git a/server/spec/cimi/model/machine_template_spec.rb b/server/spec/cimi/model/machine_template_spec.rb
new file mode 100644
index 0000000..d7028a6
--- /dev/null
+++ b/server/spec/cimi/model/machine_template_spec.rb
@@ -0,0 +1,51 @@
+# 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 'spec_helper'
+
+require 'cimi/model'
+
+describe "MachineTemplate model" do
+
+  DATA_DIR = File::join(File::dirname(__FILE__), '..', 'data')
+
+  before(:all) do
+    @xml = IO::read(File::join(DATA_DIR, "machine_template.xml"))
+    @json = IO::read(File::join(DATA_DIR, "machine_template.json"))
+  end
+
+  it "can be constructed from XML" do
+    templ = CIMI::Model::MachineTemplate.from_xml(@xml)
+    templ.should_not be_nil
+    templ.created.should == "2011-11-01"
+    templ.volumes.size.should == 1
+    templ.should serialize_to @xml, :fmt => :xml
+  end
+
+  it "should convert strings in keys to symbols when contructed from XML" do
+    templ = CIMI::Model::MachineTemplate.from_xml(@xml)
+    templ.should_not be_nil
+    templ.attribute_values.keys.each { |key| key.should be_a(Symbol) }
+  end
+
+  it "can be constructed from JSON" do
+    templ = CIMI::Model::MachineTemplate.from_json(@json)
+    templ.should_not be_nil
+
+    templ.created.should == "2011-11-01"
+    templ.should serialize_to @json, :fmt => :json
+  end
+end
diff --git a/server/spec/spec_helper.rb b/server/spec/spec_helper.rb
index 1e0dd87..d9a51f5 100644
--- a/server/spec/spec_helper.rb
+++ b/server/spec/spec_helper.rb
@@ -25,3 +25,95 @@ def parse_xml(xml, opts = {})
   opts[:keep_root] = true unless opts.has_key?(:keep_root)
   XmlSimple.xml_in(xml, opts)
 end
+
+class HashCmp
+  def initialize(exp, act)
+    @exp = exp
+    @act = act
+    @io = StringIO.new
+  end
+
+  def match?
+    @equal = true
+    compare_values(@exp, @act, [])
+    @equal
+  end
+
+  def errors
+    @io.string
+  end
+
+  private
+  def compare_values(exp, act, path)
+    if exp.is_a?(String)
+      mismatch("entries differ", exp, act, path) unless exp == act
+    elsif exp.is_a?(Array)
+      mismatch("expected array", exp, act, path) unless act.is_a?(Array)
+      unless act.size == exp.size
+        mismatch("different array lengths", exp, act, path)
+      end
+      name = path.pop
+      0.upto(exp.size-1) do |i|
+        compare_values(exp[i], act[i], path + [ "#{name}[#{i}]" ])
+      end
+    elsif exp.is_a?(Hash)
+      unless act.is_a?(Hash)
+        mismatch("expected Hash", exp, act, path)
+        return
+      end
+      unless (missing = exp.keys - act.keys).empty?
+        error "Missing key(s) at /#{path.join("/")}: #{missing.inspect}"
+      end
+      unless (excess = act.keys - exp.keys).empty?
+        error "Excess key(s) at /#{path.join("/")}: #{excess.inspect}"
+      end
+      (exp.keys - missing - excess).each do |k|
+        compare_values(exp[k], act[k], path + [ k ])
+      end
+    end
+  end
+
+  def mismatch(msg, exp, act, path)
+    error "#{msg}[#{fmt(path)}]: #{exp.inspect} != #{act.inspect}"
+  end
+
+  def error(msg)
+    @equal = false
+    @io.puts msg
+  end
+
+  def fmt(path)
+    "/#{path.join("/")}"
+  end
+end
+
+RSpec::Matchers.define :serialize_to do |exp, opts|
+  match do |act|
+    matcher(exp, act, opts[:fmt]).match?
+  end
+
+  failure_message_for_should do |act|
+    m = matcher(exp, act, opts[:fmt])
+    m.match?
+    "#{opts[:fmt].to_s.upcase} documents do not match\n" + m.errors
+  end
+
+  def matcher(exp, act, fmt)
+    raise "missing format; use :fmt => [:xml || :json]" if fmt.nil?
+    exp, act = [exp, act].map { |x| convert(x, fmt) }
+    HashCmp.new(exp, act)
+  end
+
+  def convert(x, fmt)
+    if fmt == :json
+      x = x.to_json if x.is_a?(CIMI::Model::Base)
+      x = JSON.parse(x) if x.is_a?(String)
+    elsif fmt == :xml
+      x = x.to_xml if x.is_a?(CIMI::Model::Base)
+      x = parse_xml(x)  if x.is_a?(String)
+    else
+      raise "Invalid format #{fmt}"
+    end
+    x
+  end
+end
-- 
1.7.6.4