> From: [email protected]
> To: [email protected]
> Sent: Thursday, August 2, 2012 11:07:39 AM
> Subject: [PATCH 2/4] API TESTS: adds images and instances tests
>
> From: marios <[email protected]>
>
>
> Signed-off-by: marios <[email protected]>
> ---
> tests/config.yaml | 19 ++-
> tests/deltacloud/images_test.rb | 73 ++++++++
> tests/deltacloud/instances_test.rb | 351
> ++++++++++++++++++++++++++++++++++++
> 3 files changed, 440 insertions(+), 3 deletions(-)
>
> diff --git a/tests/config.yaml b/tests/config.yaml
> index 3070b56..5f905a6 100644
> --- a/tests/config.yaml
> +++ b/tests/config.yaml
> @@ -4,15 +4,28 @@ api_url: "http://localhost:3001/api"
> mock:
> user: "mockuser"
> password: "mockpassword"
> +#OPENSTACK DRIVER CONFIG
> +openstack:
> + user:
> + password:
> + #used for instances tests:
> + instances:
> + preferred_image: "14075"
> #EC2 DRIVER CONFIG:
> ec2:
> - user: #EC2 KEY
> - password: #EC2 SECRET KEY
> + user:
> + password:
> bucket_locations:
> - #location constraint : provider
> + #location constraint
> - "EU"
> - "sa-east-1"
> - "us-west-1"
> - "us-west-2"
> - "ap-southeast-1"
> - "ap-northeast-1"
> + preferred_provider: "us-east-1"
> + #used for instances tests:
> + instances:
> + preferred_image: "ami-2b5fba42"
> + preferred_hwp: "m1.small"
> + preferred_realm: "us-east-1b"
> diff --git a/tests/deltacloud/images_test.rb
> b/tests/deltacloud/images_test.rb
> index e69de29..1313dbd 100644
> --- a/tests/deltacloud/images_test.rb
> +++ b/tests/deltacloud/images_test.rb
> @@ -0,0 +1,73 @@
> +#
> +# 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.
> +
> +$:.unshift File.join(File.dirname(__FILE__), '..')
> +require "deltacloud/test_setup.rb"
> +
> +IMAGES = "/images"
> +
> +describe 'Deltacloud API Images collection' do
> + include Deltacloud::Test::Methods
> +
> + need_collection :images
> +
> + def each_image_xml(&block)
> + res = get(IMAGES, :accept=> :xml)
> + (res.xml/'images/image').each do |r|
> + image_res = get(IMAGES + '/' + r[:id], :accept => :xml)
> + yield image_res.xml
> + end
> + end
> +
> + #Run the 'common' tests for all collections defined in
> common_tests_collections.rb
> + CommonCollectionsTest::run_common_tests_for("images")
> +
> + #Now run the images-specific tests:
> + it 'should have the "owner_id", "description", "architecure" and
> "state" element for each image' do
> + each_image_xml do |image_xml|
> + (image_xml/'state').wont_be_empty
> + (image_xml/'owner_id').wont_be_empty
> + (image_xml/'architecture').wont_be_empty
> + (image_xml/'description').wont_be_empty
> + end
> + end
> +
> + it 'should include the list of compatible hardware_profiles for
> each image' do
> + each_image_xml do |image_xml|
> + (image_xml/'hardware_profiles/hardware_profile').wont_be_empty
> + (image_xml/'hardware_profiles/hardware_profile').each do |hwp|
> + hwp[:href].wont_be_nil
> + hwp[:href].must_match /^http/
> + hwp[:id].wont_be_nil
> + hwp[:href].must_match /\/#{hwp[:id]}$/
> + hwp[:rel].must_equal 'hardware_profile'
> + end
> + end
> + end
> +
> + it 'should advertise the list of actions that can be executed for
> each image' do
> + each_image_xml do |image_xml|
> + (image_xml/'actions/link').wont_be_empty
> + (image_xml/'actions/link').each do |l|
> + l[:href].wont_be_nil
> + l[:href].must_match /^http/
> + l[:method].wont_be_nil
> + l[:rel].wont_be_nil
> + end
> + end
> + end
> +
> +end
> diff --git a/tests/deltacloud/instances_test.rb
> b/tests/deltacloud/instances_test.rb
> index e69de29..5038f28 100644
> --- a/tests/deltacloud/instances_test.rb
> +++ b/tests/deltacloud/instances_test.rb
> @@ -0,0 +1,351 @@
> +#
> +# 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.
> +
> +$:.unshift File.join(File.dirname(__FILE__), '..')
> +require "deltacloud/test_setup.rb"
> +
> +INSTANCES = "/instances"
> +
> +describe 'Deltacloud API instances collection' do
> + include Deltacloud::Test::Methods
> + need_collection :instances
> + #make sure we have at least one instance to test
> + begin
> + #keep track of what we create for deletion after tests:
> + @@created_resources = {:instances=>[], :keys=>[], :images=>[],
> :firewalls=>[]}
> + if api.instances_config["preferred_image"]
> + image_id = api.instances_config["preferred_image"]
> + else
> + image_list = get("/images", {:accept => :xml})
> + image_id = (image_list.xml/'images/image').to_a.choice[:id]
> + end
> + res = post(INSTANCES, :image_id=>image_id)
> + unless res.code == 201
> + raise Exception.new("Failed to create instance from image_id
> #{image_id}")
> + end
> + @@my_instance_id = (res.xml/'instance')[0][:id]
> + @@created_resources[:instances] << @@my_instance_id
> + end
> +
> + #stop/destroy the resources we created for the tests
> + MiniTest::Unit.after_tests {
> +puts "CLEANING UP... resources for deletion:
> #{@@created_resources.inspect}"
> + #instances:
> + @@created_resources[:instances].each_index do |i|
> + attempts = 0
> + begin
> + stop_res =
> post(INSTANCES+"/"+@@created_resources[:instances][i]+"/stop", "")
> + @@created_resources[:instances][i] = nil if stop_res.code ==
> 202
> + rescue Exception => e
> + sleep(10)
> + attempts += 1
> + retry if (attempts <= 5)
> + end
> + end
> + @@created_resources[:instances].compact!
> + @@created_resources.delete(:instances) if
> @@created_resources[:instances].empty?
> + #keys
> + [:keys, :images, :firewalls].each do |col|
> + @@created_resources[col].each do |k|
> + res = delete("/#{col}/#{k}")
> + @@created_resources[col].delete(k) if res.code == 204
> + end
> + @@created_resources.delete(col) if
> @@created_resources[col].empty?
> + end
> +puts "CLEANUP attempt finished... resources looks like:
> #{@@created_resources.inspect}"
> + raise Exception.new("Unable to delete all created resources -
> please check: #{@@created_resources.inspect}") unless
> @@created_resources.empty?
> + }
> +
> + def each_instance_xml(&block)
> + res = get(INSTANCES, :accept=> :xml)
> + (res.xml/'instances/instance').each do |r|
> + instance_res = get(INSTANCES + '/' + r[:id], :accept => :xml)
> + yield instance_res.xml
> + end
> + end
> +
> + def get_image
> + if api.instances_config["preferred_image"]
> + image_id = api.instances_config["preferred_image"]
> + else
> + image_list = get("/images", {:accept => :xml})
> + image_id = (image_list.xml/'images/image').to_a.choice[:id]
> + end
> + end
> +
> + def get_realm
> + if api.instances_config["preferred_realm"]
> + realm_id = api.instances_config["preferred_realm"]
> + else
> + realms_list = get("/realms", {:accept => :xml})
> + realm_id = (realms_list.xml/'realms/realm').to_a.choice[:id]
> + end
> + end
> +
> + def get_hwp
> + if api.instances_config["preferred_hwp"]
> + hwp_id = api.instances_config["preferred_hwp"]
> + else
> + hw_profile_list = get("/hardware_profiles", {:accept => :xml})
> + hwp_id =
> (hw_profile_list.xml/'hardware_profiles/hardware_profile').to_a.choice[:id]
> + end
> + end
> +
> + #Run the 'common' tests for all collections defined in
> common_tests_collections.rb
> + CommonCollectionsTest::run_common_tests_for("instances")
> +
> + #Now run the instances-specific tests:
> +
> + it 'must have the "state" element defined for each instance in
> collection' do
> + res = get(INSTANCES, :accept=> :xml)
> + (res.xml/'instances/instance').each do |r|
> + (r/'state').wont_be_empty
> + (r/'state').first.must_match /(RUNNING|STOPPED|PENDING)/
> + end
> + end
> +
> + it 'must have the "owner_id" element for each instance and it
> should match with the one in collection' do
> + res = get(INSTANCES, :accept=> :xml)
> + (res.xml/'instances/instance').each do |r|
> + instance_res = get(INSTANCES + '/' + r[:id], :accept => :xml)
> + (instance_res.xml/'owner_id').wont_be_empty
> +
>
> (instance_res.xml/'owner_id').first.text.must_equal((r/'owner_id').first.text)
> + end
> + end
> +
> + it 'each instance must link to the realm that was used during
> instance creation' do
> + each_instance_xml do |instance_xml|
> + (instance_xml/'realm').wont_be_empty
> + (instance_xml/'realm').size.must_equal 1
> + (instance_xml/'realm').first[:id].wont_be_nil
> + (instance_xml/'realm').first[:href].wont_be_nil
> + (instance_xml/'realm').first[:href].must_match
> /\/#{(instance_xml/'realm').first[:id]}$/
> + end
> + end
> +
> + it 'each instance must link to the image that was used to during
> instance creation' do
> + each_instance_xml do |instance_xml|
> + (instance_xml/'image').wont_be_empty
> + (instance_xml/'image').size.must_equal 1
> + (instance_xml/'image').first[:id].wont_be_nil
> + (instance_xml/'image').first[:href].wont_be_nil
> + (instance_xml/'image').first[:href].must_match
> /\/#{(instance_xml/'image').first[:id]}$/
> + end
> + end
> +
> + it 'each instance must link to the hardware_profile that was used
> to during instance creation' do
> + each_instance_xml do |instance_xml|
> + (instance_xml/'hardware_profile').wont_be_empty
> + (instance_xml/'hardware_profile').size.must_equal 1
> + (instance_xml/'hardware_profile').first[:id].wont_be_nil
> + (instance_xml/'hardware_profile').first[:href].wont_be_nil
> + (instance_xml/'hardware_profile').first[:href].must_match
> /\/#{(instance_xml/'hardware_profile').first[:id]}$/
> + end
> + end
> +
> + it 'each (NON-STOPPED) instance should advertise the public and
> private addresses of the instance' do
> + each_instance_xml do |instance_xml|
> + #skip this instance if it is in STOPPED state
> + next if (instance_xml/'instance/state').text == "STOPPED"
> + (instance_xml/'public_addresses').wont_be_empty
> + (instance_xml/'public_addresses').size.must_equal 1
> + (instance_xml/'public_addresses/address').each do |a|
> + a[:type].wont_be_nil
> + a.text.strip.wont_be_empty
> + end
> + (instance_xml/'private_addresses').wont_be_empty
> + (instance_xml/'private_addresses').size.must_equal 1
> + (instance_xml/'private_addresses/address').each do |a|
> + a[:type].wont_be_nil
> + a.text.strip.wont_be_empty
> + end
> + end
> + end
> +
> + it 'each instance should advertise the storage volumes used by the
> instance' do
> + each_instance_xml do |i|
> + (i/'storage_volumes').wont_be_empty
> + end
> + end
> +
> + it 'each instance should advertise the list of actions that can be
> executed for each instance' do
> + each_instance_xml do |instance_xml|
> + (instance_xml/'actions/link').each do |l|
> + l[:href].wont_be_nil
> + l[:href].must_match /^http/
> + l[:method].wont_be_nil
> + l[:rel].wont_be_nil
> + end
> + end
> + end
> +
> + it 'should allow to create new instance using image without realm'
> do
> + #random image and create instance
> + image_id = get_image
> + image_id.wont_be_nil
> + res = post(INSTANCES, :image_id=>image_id)
> + res.code.must_equal 201
> + res.headers[:location].wont_be_nil
> + created_instance_id = (res.xml/'instance')[0][:id]
> + #GET the instance
> + res = get(INSTANCES+"/"+created_instance_id, {:accept=>:xml})
> + res.code.must_equal 200
> + (res.xml/'instance').first[:id].must_equal created_instance_id
> + (res.xml/'instance/image').first[:id].must_equal image_id
> + #mark it for stopping after tests run:
> + @@created_resources[:instances] << created_instance_id
> + end
> +
> + it 'should allow to create new instance using image and realm' do
> + #random image, realm and create instance
> + image_id = get_image
> + image_id.wont_be_nil
> + realm_id = get_realm
> + realm_id.wont_be_nil
> + res = post(INSTANCES, :image_id=>image_id, :realm_id=>realm_id)
> + res.code.must_equal 201
> + res.headers[:location].wont_be_nil
> + created_instance_id = (res.xml/'instance')[0][:id]
> + #GET the instance
> + res = get(INSTANCES+"/"+created_instance_id, {:accept=>:xml})
> + res.code.must_equal 200
> + (res.xml/'instance').first[:id].must_equal created_instance_id
> + (res.xml/'instance/image').first[:id].must_equal image_id
> + (res.xml/'instance/realm').first[:id].must_equal realm_id
> + #mark it for stopping after tests run:
> + @@created_resources[:instances] << created_instance_id
> + end
> +
> + it 'should allow to create new instance using image, realm and
> hardware_profile' do
> + #random image, realm, hardware_profile and create instance
> + image_id = get_image
> + image_id.wont_be_nil
> + #check if this image defines compatible hw_profiles:
> + res = get("/images/"+image_id, {:accept =>:xml})
> + if (res.xml/'image/hardware_profiles').empty?
> + hwp_id = get_hwp
> + else
> + hwp_id =
> (res.xml/'image/hardware_profiles/hardware_profile').to_a.choice[:id]
> + end
> + hwp_id.wont_be_nil
> + #random realm:
> + realm_id = get_realm
> + realm_id.wont_be_nil
> + res = post(INSTANCES, :image_id=>image_id, :realm_id=>realm_id,
> :hwp_id => hwp_id)
> + res.code.must_equal 201
> + res.headers[:location].wont_be_nil
> + created_instance_id = (res.xml/'instance')[0][:id]
> + #GET the instance
> + res = get(INSTANCES+"/"+created_instance_id, {:accept=>:xml})
> + res.code.must_equal 200
> + (res.xml/'instance').first[:id].must_equal created_instance_id
> + (res.xml/'instance/image').first[:id].must_equal image_id
> + (res.xml/'instance/realm').first[:id].must_equal realm_id
> + (res.xml/'instance/hardware_profile').first[:id].must_equal
> hwp_id
> + #mark it for stopping after tests run:
> + @@created_resources[:instances] << created_instance_id
> + end
> +
> +#snapshot (make image)
> +
> + it 'should allow to snapshot running instance if supported by
> provider' do
> + #check if created instance allows creating image
> + res = get(INSTANCES+"/"+@@my_instance_id, {:accept=>:xml})
> + instance_actions =
> (res.xml/'actions/link').to_a.inject([]){|actions, current| actions
> << current[:rel]; actions}
> + skip "no create image support for instance #{@@my_instance_id}"
> unless instance_actions.include?("create_image")
> + #create image
> + res = post("/images", :instance_id => @@my_instance_id,
> :name=>random_name)
> + res.code.must_equal 201
> + my_image_id = (res.xml/'image')[0][:id]
> + #mark for deletion later:
> + @@created_resources[:images] << my_image_id
> + end
> +#
> +#create with key
> +
> + describe "create instance with auth key" do
> +
> + need_collection :keys
> + need_feature :instances, :authentication_key
> +
> + it 'should allow specification of auth key for created
> instance when supported' do
> + #create a key to use
> + key_name = random_name
> + key_res = post("/keys", :name=>key_name)
> + key_res.code.must_equal 201
> + key_id = (key_res.xml/'key')[0][:id]
> + #create instance with this key:
> + image_id = get_image
> + res = post(INSTANCES, :image_id => image_id, :keyname =>
> key_id)
> + res.code.must_equal 201
> + instance_id = (res.xml/'instance')[0][:id]
> + #check the key:
> + key_used =
> (res.xml/'instance/authentication/login/keyname')[0].text
> + key_used.must_equal key_id
> + #mark them for deletion after tests run:
> + @@created_resources[:instances] << instance_id
> + @@created_resources[:keys] << key_id
> + end
> +
> + end
> +
> +#specify user name (feature)
> + describe "create instance with user defined name" do
> +
> + need_feature :instances, :user_name
> +
> + it 'should allow specification of name for created instance when
> supported' do
> + instance_name = random_name
> + image_id = get_image
> + res = post(INSTANCES, :image_id => image_id, :name =>
> instance_name)
> + res.code.must_equal 201
> + instance_id = (res.xml/'instance')[0][:id]
> + #check the name:
> + created_name = (res.xml/'instance/name')[0].text
> + created_name.must_equal instance_name
> + #mark for deletion:
> + @@created_resources[:instances] << instance_id
> + end
> + end
> +
> +#create with firewall (feature)
> + describe "create instance with firewall" do
> +
> + need_collection :firewalls
> + need_feature :instances, :firewalls
> +
> + it 'should be able to create instance using specified firewall'
> do
> + #create a firewall to use
> + fw_name = random_name
> + fw_res = post("/firewalls", :name=>fw_name,
> :description=>"firewall created for instances API test on
> #{Time.now}")
> + fw_res.code.must_equal 201
> + fw_id = (fw_res.xml/'firewall')[0][:id]
> + ((fw_res.xml/'firewall/name')[0].text).must_equal fw_name
> + #create instance with this firewall:
> + image_id = get_image
> + res = post(INSTANCES, :image_id => image_id, :firewalls1 =>
> fw_id)
> + res.code.must_equal 201
> + instance_id = (res.xml/'instance')[0][:id]
> + #check the firewall:
> + fw_used = (res.xml/'instance/firewalls/firewall')[0][:id]
> + fw_used.must_equal fw_id
> + #mark for deletion:
> + @@created_resources[:instances] << instance_id
> + @@created_resources[:firewalls] << fw_id
> + end
> +
> + end
> +end
> --
> 1.7.6.5
>
>
Running >> rake test:deltacloud
returns the error below (irrespective of the driver - tried mock and vsphere).
Running >> rake test:deltacloud:images TEST_OPTS="-v"
works for me.
-----------------
/home/dcloud/workspace/deltacloud/tests/deltacloud/instances_test.rb:28:
warning: class variable access from toplevel
/home/dcloud/workspace/deltacloud/tests/deltacloud/instances_test.rb:33:in
`block in <top (required)>': undefined method `choice' for
#<Array:0x00000001bc0768> (NoMethodError)
from
/usr/local/share/gems/gems/minitest-3.3.0/lib/minitest/spec.rb:71:in
`class_eval'
from
/usr/local/share/gems/gems/minitest-3.3.0/lib/minitest/spec.rb:71:in `describe'
from
/home/dcloud/workspace/deltacloud/tests/deltacloud/instances_test.rb:22:in
`<top (required)>'
from /usr/share/rubygems/rubygems/custom_require.rb:36:in `require'
from /usr/share/rubygems/rubygems/custom_require.rb:36:in `require'
from
/usr/local/share/gems/gems/rake-0.9.2.2/lib/rake/rake_test_loader.rb:15:in
`block in <main>'
from
/usr/local/share/gems/gems/rake-0.9.2.2/lib/rake/rake_test_loader.rb:4:in
`select'
from
/usr/local/share/gems/gems/rake-0.9.2.2/lib/rake/rake_test_loader.rb:4:in
`<main>'
rake aborted!
Command failed with status (1): [/usr/bin/ruby -I"lib" -I"/usr/local/share/...]
Tasks: TOP => test:deltacloud
(See full trace by running task with --trace)