You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by mf...@redhat.com on 2012/05/24 16:56:36 UTC
[PATCH core 1/2] Ec2: Added minitest suite for EC2 driver using VCR recording
From: Michal Fojtik <mf...@redhat.com>
Signed-off-by: Michal fojtik <mf...@redhat.com>
---
server/Rakefile | 2 +-
server/tests/drivers/ec2/api_test.rb | 128 +++++++
server/tests/drivers/ec2/common.rb | 69 ++++
server/tests/drivers/ec2/drivers_test.rb | 120 +++++++
server/tests/drivers/ec2/hardware_profiles_test.rb | 224 ++++++++++++
server/tests/drivers/ec2/images_test.rb | 230 +++++++++++++
server/tests/drivers/ec2/instances_test.rb | 356 ++++++++++++++++++++
server/tests/drivers/ec2/keys_test.rb | 181 ++++++++++
server/tests/drivers/ec2/realms_test.rb | 146 ++++++++
9 files changed, 1455 insertions(+), 1 deletion(-)
create mode 100644 server/tests/drivers/ec2/api_test.rb
create mode 100644 server/tests/drivers/ec2/common.rb
create mode 100644 server/tests/drivers/ec2/drivers_test.rb
create mode 100644 server/tests/drivers/ec2/hardware_profiles_test.rb
create mode 100644 server/tests/drivers/ec2/images_test.rb
create mode 100644 server/tests/drivers/ec2/instances_test.rb
create mode 100644 server/tests/drivers/ec2/keys_test.rb
create mode 100644 server/tests/drivers/ec2/realms_test.rb
diff --git a/server/Rakefile b/server/Rakefile
index 8223e5e..ded7d8b 100644
--- a/server/Rakefile
+++ b/server/Rakefile
@@ -226,7 +226,7 @@ end
namespace :test do
- %w(mock rackspace rhevm openstack google fgcp).each do |driver|
+ %w(mock rackspace rhevm openstack google fgcp ec2).each do |driver|
desc "Run #{driver} unit tests"
Rake::TestTask.new(driver) { |t|
t.test_files = FileList.new("tests/drivers/#{driver}/*_test.rb")
diff --git a/server/tests/drivers/ec2/api_test.rb b/server/tests/drivers/ec2/api_test.rb
new file mode 100644
index 0000000..a5b2333
--- /dev/null
+++ b/server/tests/drivers/ec2/api_test.rb
@@ -0,0 +1,128 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/ec2/common'
+
+describe 'Deltacloud API' do
+
+ before do
+ Timecop.freeze(FREEZED_TIME)
+ VCR.insert_cassette __name__
+ end
+
+ after do
+ VCR.eject_cassette
+ end
+
+ include Deltacloud::Test
+
+ it 'return HTTP_OK when accessing API entrypoint' do
+ get Deltacloud[:root_url]
+ last_response.status.must_equal 200
+ end
+
+ it 'advertise the current driver in API entrypoint' do
+ get Deltacloud[:root_url]
+ xml_response.root[:driver].must_equal ENV['API_DRIVER']
+ end
+
+ it 'advertise the current API version in API entrypoint' do
+ get Deltacloud[:root_url]
+ xml_response.root[:version].must_equal Deltacloud[:version]
+ end
+
+ it 'advertise the current API version in HTTP headers' do
+ get Deltacloud[:root_url]
+ last_response.headers['Server'].must_equal "Apache-Deltacloud/#{Deltacloud[:version]}"
+ end
+
+ it 'must include the ETag in HTTP headers' do
+ get Deltacloud[:root_url]
+ last_response.headers['ETag'].wont_be_nil
+ end
+
+ it 'advertise collections in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link').wont_be_empty
+ end
+
+ it 'include the :href and :rel attribute for each collection in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link').each do |collection|
+ collection[:href].wont_be_nil
+ collection[:rel].wont_be_nil
+ end
+ end
+
+ it 'uses the absolute URI in the :href attribute for each collection in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link').each do |collection|
+ collection[:href].must_match /^http/
+ end
+ end
+
+ it 'advertise features for some collections in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link/feature').wont_be_empty
+ end
+
+ it 'advertise the name of the feature for some collections in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link/feature').each do |f|
+ f[:name].wont_be_nil
+ end
+ end
+
+ it 'must change the media type from XML to JSON using Accept headers' do
+ header 'Accept', 'application/json'
+ get Deltacloud[:root_url]
+ last_response.headers['Content-Type'].must_equal 'application/json'
+ end
+
+ it 'must change the media type to JSON using the "?format" parameter in URL' do
+ get Deltacloud[:root_url], { :format => 'json' }
+ last_response.headers['Content-Type'].must_equal 'application/json'
+ end
+
+ it 'must change the driver when using X-Deltacloud-Driver HTTP header' do
+ header 'X-Deltacloud-Driver', 'ec2'
+ get Deltacloud[:root_url]
+ xml_response.root[:driver].must_equal 'ec2'
+ header 'X-Deltacloud-Driver', 'mock'
+ get Deltacloud[:root_url]
+ xml_response.root[:driver].must_equal 'mock'
+ end
+
+ it 'must change the features when driver is swapped using HTTP headers' do
+ header 'X-Deltacloud-Driver', 'ec2'
+ get Deltacloud[:root_url]
+ # The 'user_name' feature is not supported currently for the EC2 driver
+ (xml_response/'api/link/feature').map { |f| f[:name] }.wont_include 'user_name'
+ header 'X-Deltacloud-Driver', 'mock'
+ get Deltacloud[:root_url]
+ # But it's supported in Mock driver
+ (xml_response/'api/link/feature').map { |f| f[:name] }.must_include 'user_name'
+ end
+
+ it 'must re-validate the driver credentials when using "?force_auth" parameter in URL' do
+ get Deltacloud[:root_url], { :force_auth => '1' }
+ last_response.status.must_equal 401
+ auth_as_mock
+ get Deltacloud[:root_url], { :force_auth => '1' }
+ last_response.status.must_equal 200
+ end
+
+ it 'must change the API PROVIDER using the /api;provider matrix parameter in URI' do
+ get Deltacloud[:root_url] + ';provider=test1'
+ xml_response.root[:provider].wont_be_nil
+ xml_response.root[:provider].must_equal 'test1'
+ get Deltacloud[:root_url] + ';provider=test2'
+ xml_response.root[:provider].must_equal 'test2'
+ end
+
+ it 'must change the API DRIVER using the /api;driver matrix parameter in URI' do
+ get Deltacloud[:root_url] + ';driver=ec2'
+ xml_response.root[:driver].must_equal 'ec2'
+ get Deltacloud[:root_url] + ';driver=mock'
+ xml_response.root[:driver].must_equal 'mock'
+ end
+
+end
diff --git a/server/tests/drivers/ec2/common.rb b/server/tests/drivers/ec2/common.rb
new file mode 100644
index 0000000..83f315b
--- /dev/null
+++ b/server/tests/drivers/ec2/common.rb
@@ -0,0 +1,69 @@
+ENV['API_DRIVER'] = 'ec2'
+ENV['API_USERNAME'] = 'AKIAI77KNAA7ZXRLL7GQ'
+ENV['API_PASSWORD'] = 'idJ9vktNaDWAK0LWVVE/526ONvJmTl2Crto/s8Ok'
+ENV['RACK_ENV'] = 'test'
+
+load File.join(File.dirname(__FILE__), '..', '..', '..', 'lib', 'deltacloud_rack.rb')
+
+Deltacloud::configure do |server|
+ server.root_url '/api'
+ server.version '0.5.0'
+ server.klass 'Deltacloud::API'
+end.require_frontend!
+
+require 'minitest/autorun'
+require 'rack/test'
+require 'nokogiri'
+require 'json'
+require 'pp'
+require 'vcr'
+require 'timecop'
+
+VCR.configure do |c|
+ c.cassette_library_dir = File.join(File.dirname(__FILE__), 'fixtures')
+ c.hook_into :webmock
+ c.default_cassette_options = { :record => :new_episodes }
+ #c.default_cassette_options = { :record => :none }
+end
+
+# Let's set time that timecop will use to freeze
+# Time.now will then return this time instead of 'real' system time
+
+FREEZED_TIME = Time.local(2012, 5, 24, 18, 10, 0).freeze
+
+module Deltacloud
+ module Test
+ include Rack::Test::Methods
+
+ def included?(sub)
+ sub.class_eval do
+ before do
+ header 'Accept', 'application/xml'
+ end
+ end
+ end
+
+ def xml_response
+ Nokogiri::XML(last_response.body)
+ end
+
+ def auth_as_mock
+ authorize ENV['API_USERNAME'], ENV['API_PASSWORD']
+ end
+
+ def collection_url(collection)
+ [Deltacloud[:root_url], collection.to_s].join('/')
+ end
+
+ def app
+ Rack::Builder.new {
+ map '/' do
+ Timecop.freeze(FREEZED_TIME) do
+ use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+ run Rack::Cascade.new([Deltacloud::API])
+ end
+ end
+ }
+ end
+ end
+end
diff --git a/server/tests/drivers/ec2/drivers_test.rb b/server/tests/drivers/ec2/drivers_test.rb
new file mode 100644
index 0000000..26adc7b
--- /dev/null
+++ b/server/tests/drivers/ec2/drivers_test.rb
@@ -0,0 +1,120 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/ec2/common'
+
+describe 'Deltacloud API drivers' do
+ include Deltacloud::Test
+ before do
+ Timecop.freeze(FREEZED_TIME)
+ VCR.insert_cassette __name__
+ end
+
+ after do
+ VCR.eject_cassette
+ end
+
+ it 'must advertise have the drivers collection in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link[@rel=drivers]').wont_be_empty
+ end
+
+ it 'must not require authentication to access the "driver" collection' do
+ get collection_url(:drivers)
+ last_response.status.must_equal 200
+ end
+
+ it 'should respond with HTTP_OK when accessing the :drivers collection with authentication' do
+ get collection_url(:drivers)
+ last_response.status.must_equal 200
+ end
+
+ it 'should support the JSON media type' do
+ header 'Accept', 'application/json'
+ get collection_url(:drivers)
+ last_response.status.must_equal 200
+ last_response.headers['Content-Type'].must_equal 'application/json'
+ end
+
+ it 'must include the ETag in HTTP headers' do
+ get collection_url(:drivers)
+ last_response.headers['ETag'].wont_be_nil
+ end
+
+ it 'must have the "drivers" element on top level' do
+ get collection_url(:drivers)
+ xml_response.root.name.must_equal 'drivers'
+ end
+
+ it 'must have some "driver" elements inside "drivers"' do
+ get collection_url(:drivers)
+ (xml_response/'drivers/driver').wont_be_empty
+ end
+
+ it 'must provide the :id attribute for each driver in collection' do
+ get collection_url(:drivers)
+ (xml_response/'drivers/driver').each do |r|
+ r[:id].wont_be_nil
+ end
+ end
+
+ it 'must include the :href attribute for each "driver" element in collection' do
+ get collection_url(:drivers)
+ (xml_response/'drivers/driver').each do |r|
+ r[:href].wont_be_nil
+ end
+ end
+
+ it 'must use the absolute URL in each :href attribute' do
+ get collection_url(:drivers)
+ (xml_response/'drivers/driver').each do |r|
+ r[:href].must_match /^http/
+ end
+ end
+
+ it 'must have the URL ending with the :id of the driver' do
+ get collection_url(:drivers)
+ (xml_response/'drivers/driver').each do |r|
+ r[:href].must_match /#{r[:id]}$/
+ end
+ end
+
+ it 'must return the list of valid parameters for the :index action' do
+ options collection_url(:drivers) + '/index'
+ last_response.headers['Allow'].wont_be_nil
+ end
+
+ it 'must have the "name" element defined for each driver in collection' do
+ get collection_url(:drivers)
+ (xml_response/'drivers/driver').each do |r|
+ (r/'name').wont_be_nil
+ end
+ end
+
+
+ it 'must return the full "driver" when following the URL in driver element' do
+ auth_as_mock
+ get collection_url(:drivers)
+ (xml_response/'drivers/driver').each do |r|
+ get collection_url(:drivers) + '/' + r[:id]
+ last_response.status.must_equal 200
+ end
+ end
+
+ it 'must have the "name" element for the driver and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:drivers)
+ (xml_response/'drivers/driver').each do |r|
+ r[:id].wont_be_nil
+ get collection_url(:drivers) + '/' + r[:id]
+ (xml_response/'name').wont_be_empty
+ (xml_response/'name').first.text.must_equal((r/'name').first.text)
+ end
+ end
+
+ it 'should advertise available providers for some drivers' do
+ get collection_url(:drivers)
+ (xml_response/'drivers/driver/provider').each do |p|
+ p[:id].wont_be_nil
+ end
+ end
+
+end
diff --git a/server/tests/drivers/ec2/hardware_profiles_test.rb b/server/tests/drivers/ec2/hardware_profiles_test.rb
new file mode 100644
index 0000000..efafa72
--- /dev/null
+++ b/server/tests/drivers/ec2/hardware_profiles_test.rb
@@ -0,0 +1,224 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/ec2/common'
+
+describe 'Deltacloud API Hardware Profiles' do
+ include Deltacloud::Test
+
+ it 'must advertise have the hardware_profiles collection in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link[@rel=hardware_profiles]').wont_be_empty
+ end
+
+ it 'should respond with HTTP_OK when accessing the :hardware_profiles collection with authentication' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ last_response.status.must_equal 200
+ end
+
+ it 'should support the JSON media type' do
+ auth_as_mock
+ header 'Accept', 'application/json'
+ get collection_url(:hardware_profiles)
+ last_response.status.must_equal 200
+ last_response.headers['Content-Type'].must_equal 'application/json'
+ end
+
+ it 'must include the ETag in HTTP headers' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ last_response.headers['ETag'].wont_be_nil
+ end
+
+ it 'must have the "hardware_profiles" element on top level' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ xml_response.root.name.must_equal 'hardware_profiles'
+ end
+
+ it 'must have some "hardware_profile" elements inside "hardware_profiles"' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').wont_be_empty
+ end
+
+ it 'must provide the :id attribute for each hardware_profile in collection' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ r[:id].wont_be_nil
+ end
+ end
+
+ it 'must include the :href attribute for each "hardware_profile" element in collection' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ r[:href].wont_be_nil
+ end
+ end
+
+ it 'must use the absolute URL in each :href attribute' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ r[:href].must_match /^http/
+ end
+ end
+
+ it 'must have the URL ending with the :id of the hardware_profile' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ r[:href].must_match /#{r[:id]}$/
+ end
+ end
+
+ it 'must return the list of valid parameters for the :index action' do
+ auth_as_mock
+ options collection_url(:hardware_profiles) + '/index'
+ last_response.headers['Allow'].wont_be_nil
+ end
+
+ it 'must have the "name" element defined for each hardware_profile in collection' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ (r/'name').wont_be_empty
+ end
+ end
+
+ it 'should have the "property" element defined if not the opaque hardware_profile' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ next if r[:id] == 'opaque'
+ (r/'property').wont_be_empty
+ end
+ end
+
+ it 'must define the :kind attribute for each "property" ' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ next if r[:id] == 'opaque'
+ (r/'property').each { |p| p[:kind].wont_be_nil }
+ end
+ end
+
+ it 'must define the :name attribute for each "property" ' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ next if r[:id] == 'opaque'
+ (r/'property').each { |p| p[:name].wont_be_nil }
+ end
+ end
+
+ it 'must define the :unit attribute for each "property" ' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ next if r[:id] == 'opaque'
+ (r/'property').each { |p| p[:unit].wont_be_nil }
+ end
+ end
+
+ it 'must define the :value attribute for each "property" ' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ next if r[:id] == 'opaque'
+ (r/'property').each { |p| p[:value].wont_be_nil }
+ end
+ end
+
+ it 'must define the "param" element if property kind is not "fixed"' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ next if r[:id] == 'opaque'
+ (r/'property').each do |p|
+ next if p[:kind] == 'fixed'
+ (p/'param').wont_be_empty
+ (p/'param').size.must_equal 1
+ (p/'param').first[:href].wont_be_nil
+ (p/'param').first[:href].must_match /^http/
+ (p/'param').first[:method].wont_be_nil
+ (p/'param').first[:name].wont_be_nil
+ (p/'param').first[:operation].wont_be_nil
+ end
+ end
+ end
+
+ it 'must provide the list of valid values when the property is defined as "enum"' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ next if r[:id] == 'opaque'
+ (r/'property').each do |p|
+ next if p[:kind] != 'enum'
+ (p/'enum/entry').wont_be_empty
+ (p/'enum/entry').each { |e| e[:value].wont_be_nil }
+ end
+ end
+ end
+
+ it 'must provide the range of valid values when the property is defined as "range"' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ next if r[:id] == 'opaque'
+ (r/'property').each do |p|
+ next if p[:kind] != 'range'
+ (p/'range').wont_be_empty
+ (p/'range').size.must_equal 1
+ (p/'range').first[:first].wont_be_nil
+ (p/'range').first[:last].wont_be_nil
+ end
+ end
+ end
+
+ it 'must provide the default value within the range if property defined as "range"' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ next if r[:id] == 'opaque'
+ (r/'property').each do |p|
+ next if p[:kind] != 'range'
+ ((p/'range').first[:first].to_i..(p/'range').first[:last].to_i).include?(p[:value].to_i).must_equal true
+ end
+ end
+ end
+
+ it 'must provide the default value that is included in enum list if property defined as "enum"' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ next if r[:id] == 'opaque'
+ (r/'property').each do |p|
+ next if p[:kind] != 'enum'
+ (p/'enum/entry').map { |e| e[:value] }.include?(p[:value]).must_equal true
+ end
+ end
+ end
+
+ it 'must return the full "hardware_profile" when following the URL in hardware_profile element' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ get collection_url(:hardware_profiles) + '/' + r[:id]
+ last_response.status.must_equal 200
+ end
+ end
+
+ it 'must have the "name" element for the hardware_profile and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:hardware_profiles)
+ (xml_response/'hardware_profiles/hardware_profile').each do |r|
+ get collection_url(:hardware_profiles) + '/' + r[:id]
+ (xml_response/'name').wont_be_empty
+ (xml_response/'name').first.text.must_equal((r/'name').first.text)
+ end
+ end
+
+end
diff --git a/server/tests/drivers/ec2/images_test.rb b/server/tests/drivers/ec2/images_test.rb
new file mode 100644
index 0000000..34884fa
--- /dev/null
+++ b/server/tests/drivers/ec2/images_test.rb
@@ -0,0 +1,230 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/ec2/common'
+
+describe 'Deltacloud API Images' do
+ before do
+ Timecop.freeze(FREEZED_TIME)
+ VCR.insert_cassette __name__
+ end
+
+ after do
+ VCR.eject_cassette
+ end
+
+ include Deltacloud::Test
+
+ it 'must advertise have the images collection in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link[@rel=images]').wont_be_empty
+ end
+
+ it 'must require authentication to access the "image" collection' do
+ get collection_url(:images)
+ last_response.status.must_equal 401
+ end
+
+ it 'should respond with HTTP_OK when accessing the :images collection with authentication' do
+ auth_as_mock
+ get collection_url(:images)
+ last_response.status.must_equal 200
+ end
+
+ it 'should support the JSON media type' do
+ auth_as_mock
+ header 'Accept', 'application/json'
+ get collection_url(:images)
+ last_response.status.must_equal 200
+ last_response.headers['Content-Type'].must_equal 'application/json'
+ end
+
+ it 'must include the ETag in HTTP headers' do
+ auth_as_mock
+ get collection_url(:images)
+ last_response.headers['ETag'].wont_be_nil
+ end
+
+ it 'must have the "images" element on top level' do
+ auth_as_mock
+ get collection_url(:images)
+ xml_response.root.name.must_equal 'images'
+ end
+
+ it 'must have some "image" elements inside "images"' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').wont_be_empty
+ end
+
+ it 'must provide the :id attribute for each image in collection' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').each do |r|
+ r[:id].wont_be_nil
+ end
+ end
+
+ it 'must include the :href attribute for each "image" element in collection' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').each do |r|
+ r[:href].wont_be_nil
+ end
+ end
+
+ it 'must use the absolute URL in each :href attribute' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').each do |r|
+ r[:href].must_match /^http/
+ end
+ end
+
+ it 'must have the URL ending with the :id of the image' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').each do |r|
+ r[:href].must_match /#{r[:id]}$/
+ end
+ end
+
+ it 'must return the list of valid parameters for the :index action' do
+ auth_as_mock
+ options collection_url(:images) + '/index'
+ last_response.headers['Allow'].wont_be_nil
+ end
+
+ it 'must have the "name" element defined for each image in collection' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').each do |r|
+ (r/'name').wont_be_empty
+ end
+ end
+
+ it 'must have the "state" element defined for each image in collection' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').each do |r|
+ (r/'state').wont_be_empty
+ end
+ end
+
+ it 'must return the full "image" when following the URL in image element' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').wont_be_empty
+ (xml_response/'images/image')[0..10].each do |r|
+ VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
+ get collection_url(:images) + '/' + r[:id]
+ end
+ last_response.status.must_equal 200
+ end
+ end
+
+ it 'must have the "name" element for the image and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').wont_be_empty
+ (xml_response/'images/image')[0..10].each do |r|
+ VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
+ get collection_url(:images) + '/' + r[:id]
+ end
+ (xml_response/'name').wont_be_empty
+ (xml_response/'name').first.text.must_equal((r/'name').first.text)
+ end
+ end
+
+ it 'must have the "name" element for the image and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').wont_be_empty
+ (xml_response/'images/image')[0..10].each do |r|
+ VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
+ get collection_url(:images) + '/' + r[:id]
+ end
+ (xml_response/'state').wont_be_empty
+ (xml_response/'state').first.text.must_equal((r/'state').first.text)
+ end
+ end
+
+ it 'should have the "owner_id" element for each image' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').wont_be_empty
+ (xml_response/'images/image')[0..10].each do |r|
+ VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
+ get collection_url(:images) + '/' + r[:id]
+ end
+ (xml_response/'owner_id').wont_be_empty
+ end
+ end
+
+ it 'should have the "description" element for each image' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').wont_be_empty
+ (xml_response/'images/image')[0..10].each do |r|
+ VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
+ get collection_url(:images) + '/' + r[:id]
+ end
+ (xml_response/'description').wont_be_empty
+ end
+ end
+
+ it 'should have the "architecture" element for each image' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').wont_be_empty
+ (xml_response/'images/image')[0..10].each do |r|
+ VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
+ get collection_url(:images) + '/' + r[:id]
+ end
+ (xml_response/'architecture').wont_be_empty
+ end
+ end
+
+ it 'should include the list of compatible hardware_profiles for each image' do
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').wont_be_empty
+ (xml_response/'images/image')[0..10].each do |r|
+ VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
+ get collection_url(:images) + '/' + r[:id]
+ end
+ (xml_response/'hardware_profiles/hardware_profile').wont_be_empty
+ (xml_response/'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
+ auth_as_mock
+ get collection_url(:images)
+ (xml_response/'images/image').wont_be_empty
+ (xml_response/'images/image')[0..10].each do |r|
+ VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
+ get collection_url(:images) + '/' + r[:id]
+ end
+ (xml_response/'actions/link').wont_be_empty
+ (xml_response/'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 give client HTML form to create new image' do
+ auth_as_mock
+ header 'Accept', 'text/html'
+ get collection_url(:images) + '/new'
+ last_response.status.must_equal 200
+ end
+
+end
diff --git a/server/tests/drivers/ec2/instances_test.rb b/server/tests/drivers/ec2/instances_test.rb
new file mode 100644
index 0000000..e0388f0
--- /dev/null
+++ b/server/tests/drivers/ec2/instances_test.rb
@@ -0,0 +1,356 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/ec2/common'
+
+describe 'Deltacloud API instances' do
+ include Deltacloud::Test
+
+ before do
+ Timecop.freeze(FREEZED_TIME)
+ VCR.insert_cassette __name__
+ end
+
+ after do
+ VCR.eject_cassette
+ end
+
+ it 'must advertise have the instances collection in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link[@rel=instances]').wont_be_empty
+ end
+
+
+ it 'must require authentication to access the "instance" collection' do
+ get collection_url(:instances)
+ last_response.status.must_equal 401
+ end
+
+ it 'should respond with HTTP_OK when accessing the :instances collection with authentication' do
+ auth_as_mock
+ get collection_url(:instances)
+ last_response.status.must_equal 200
+ end
+
+ it 'should support the JSON media type' do
+ auth_as_mock
+ header 'Accept', 'application/json'
+ get collection_url(:instances)
+ last_response.status.must_equal 200
+ last_response.headers['Content-Type'].must_equal 'application/json'
+ end
+
+ it 'must include the ETag in HTTP headers' do
+ auth_as_mock
+ get collection_url(:instances)
+ last_response.headers['ETag'].wont_be_nil
+ end
+
+ it 'must have the "instances" element on top level' do
+ auth_as_mock
+ get collection_url(:instances)
+ xml_response.root.name.must_equal 'instances'
+ end
+
+ it 'must have some "instance" elements inside "instances"' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').wont_be_empty
+ end
+
+ it 'must provide the :id attribute for each instance in collection' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ r[:id].wont_be_nil
+ end
+ end
+
+ it 'must include the :href attribute for each "instance" element in collection' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ r[:href].wont_be_nil
+ end
+ end
+
+ it 'must use the absolute URL in each :href attribute' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ r[:href].must_match /^http/
+ end
+ end
+
+ it 'must have the URL ending with the :id of the instance' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ r[:href].must_match /#{r[:id]}$/
+ end
+ end
+
+ it 'must return the list of valid parameters for the :index action' do
+ auth_as_mock
+ options collection_url(:instances) + '/index'
+ last_response.headers['Allow'].wont_be_nil
+ end
+
+ it 'must have the "name" element defined for each instance in collection' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ (r/'name').wont_be_empty
+ end
+ end
+
+ it 'must have the "state" element defined for each instance in collection' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ (r/'state').wont_be_empty
+ (r/'state').first.must_match /(RUNNING|STOPPED|PENDING)/
+ end
+ end
+
+
+ it 'must return the full "instance" when following the URL in instance element' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
+ get collection_url(:instances) + '/' + r[:id]
+ end
+ last_response.status.must_equal 200
+ end
+ end
+
+
+ it 'must have the "name" element for the instance and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
+ get collection_url(:instances) + '/' + r[:id]
+ end
+ (xml_response/'name').wont_be_empty
+ (xml_response/'name').first.text.must_equal((r/'name').first.text)
+ end
+ end
+
+ it 'must have the "name" element for the instance and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
+ get collection_url(:instances) + '/' + r[:id]
+ end
+ (xml_response/'state').wont_be_empty
+ (xml_response/'state').first.text.must_equal((r/'state').first.text)
+ end
+ end
+
+ it 'must have the "owner_id" element for the instance and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
+ get collection_url(:instances) + '/' + r[:id]
+ end
+ (xml_response/'owner_id').wont_be_empty
+ (xml_response/'owner_id').first.text.must_equal((r/'owner_id').first.text)
+ end
+ end
+
+ it 'must link to the realm that was used to during instance creation' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
+ get collection_url(:instances) + '/' + r[:id]
+ end
+ (xml_response/'realm').wont_be_empty
+ (xml_response/'realm').size.must_equal 1
+ (xml_response/'realm').first[:id].wont_be_nil
+ (xml_response/'realm').first[:href].wont_be_nil
+ (xml_response/'realm').first[:href].must_match /\/#{(xml_response/'realm').first[:id]}$/
+ end
+ end
+
+ it 'must link to the image that was used to during instance creation' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
+ get collection_url(:instances) + '/' + r[:id]
+ end
+ (xml_response/'image').wont_be_empty
+ (xml_response/'image').size.must_equal 1
+ (xml_response/'image').first[:id].wont_be_nil
+ (xml_response/'image').first[:href].wont_be_nil
+ (xml_response/'image').first[:href].must_match /\/#{(xml_response/'image').first[:id]}$/
+ end
+ end
+
+ it 'must link to the hardware_profile that was used to during instance creation' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
+ get collection_url(:instances) + '/' + r[:id]
+ end
+ (xml_response/'hardware_profile').wont_be_empty
+ (xml_response/'hardware_profile').size.must_equal 1
+ (xml_response/'hardware_profile').first[:id].wont_be_nil
+ (xml_response/'hardware_profile').first[:href].wont_be_nil
+ (xml_response/'hardware_profile').first[:href].must_match /\/#{(xml_response/'hardware_profile').first[:id]}$/
+ end
+ end
+
+ it 'should advertise the public and private addresses of the instance' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance[@state=RUNNING]').each do |r|
+ VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
+ get collection_url(:instances) + '/' + r[:id]
+ end
+ puts xml_response
+ (xml_response/'public_addresses').wont_be_empty
+ (xml_response/'public_addresses').size.must_equal 1
+ (xml_response/'public_addresses/address').each do |a|
+ a[:type].wont_be_nil
+ a.text.strip.wont_be_empty
+ end
+ (xml_response/'private_addresses').wont_be_empty
+ (xml_response/'private_addresses').size.must_equal 1
+ (xml_response/'private_addresses/address').each do |a|
+ a[:type].wont_be_nil
+ a.text.strip.wont_be_empty
+ end
+ end
+ end
+
+ it 'should advertise the storage volumes used by the instance' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
+ get collection_url(:instances) + '/' + r[:id]
+ end
+ (xml_response/'storage_volumes').wont_be_empty
+ end
+ end
+
+ it 'should advertise the list of actions that can be executed for each instance' do
+ auth_as_mock
+ get collection_url(:instances)
+ (xml_response/'instances/instance').each do |r|
+ VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
+ get collection_url(:instances) + '/' + r[:id]
+ end
+ (xml_response/'actions/link').wont_be_empty
+ (xml_response/'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 and destroy new instance using the image without realm' do
+ auth_as_mock
+ image_id = 'ami-e565ba8c'
+ VCR.use_cassette "#{__name__}_create_instance" do
+ post collection_url(:instances), { :image_id => image_id }
+ end
+ last_response.status.must_equal 201 # HTTP_CREATED
+ last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+ instance_id = last_response.headers['Location'].split('/').last
+ # Get the instance and check if ID and image is set correctly
+ VCR.use_cassette "#{__name__}_get_instance" do
+ get collection_url(:instances) + '/' + instance_id
+ end
+ last_response.status.must_equal 200 # HTTP_OK
+ (xml_response/'instance').first[:id].must_equal instance_id
+ (xml_response/'instance/image').first[:id].must_equal image_id
+ 10.times do |i|
+ VCR.use_cassette "#{__name__}_pool_#{i}_instance" do
+ get collection_url(:instances) + '/' + instance_id
+ end
+ break if (xml_response/'instance/state').text == 'RUNNING'
+ sleep(10)
+ end
+ (xml_response/'instance/state').text.must_equal 'RUNNING'
+ # Delete created instance
+ VCR.use_cassette "#{__name__}_delete_instance" do
+ post collection_url(:instances) + '/' + instance_id + '/stop'
+ end
+ last_response.status.must_equal 202 # HTTP_NO_CONTENT
+ end
+
+ it 'should allow to create and destroy new instance using the image within realm' do
+ auth_as_mock
+ image_id = 'ami-e565ba8c'
+ realm_id = 'us-east-1c'
+ VCR.use_cassette "#{__name__}_create_instance" do
+ post collection_url(:instances), { :image_id => image_id, :realm_id => realm_id }
+ end
+ last_response.status.must_equal 201 # HTTP_CREATED
+ last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+ instance_id = last_response.headers['Location'].split('/').last
+ # Get the instance and check if ID and image is set correctly
+ VCR.use_cassette "#{__name__}_get_instance" do
+ get collection_url(:instances) + '/' + instance_id
+ end
+ last_response.status.must_equal 200 # HTTP_OK
+ (xml_response/'instance').first[:id].must_equal instance_id
+ (xml_response/'instance/image').first[:id].must_equal image_id
+ 10.times do |i|
+ VCR.use_cassette "#{__name__}_pool_#{i}_instance" do
+ get collection_url(:instances) + '/' + instance_id
+ end
+ break if (xml_response/'instance/state').text == 'RUNNING'
+ sleep(10)
+ end
+ (xml_response/'instance/state').text.must_equal 'RUNNING'
+ (xml_response/'instance/realm').first[:id].must_equal realm_id
+ # Delete created instance
+ VCR.use_cassette "#{__name__}_delete_instance" do
+ post collection_url(:instances) + '/' + instance_id + '/stop'
+ end
+ last_response.status.must_equal 202 # HTTP_NO_CONTENT
+ end
+
+ it 'should allow to create and destroy new instance using the first available image and first hardware_profile' do
+ auth_as_mock
+ image_id = 'ami-e565ba8c'
+ hwp_id = 'm1.small'
+ VCR.use_cassette "#{__name__}_create_instance" do
+ post collection_url(:instances), { :image_id => image_id, :hwp_id => hwp_id }
+ end
+ last_response.status.must_equal 201 # HTTP_CREATED
+ last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+ instance_id = last_response.headers['Location'].split('/').last
+ # Get the instance and check if ID and image is set correctly
+ VCR.use_cassette "#{__name__}_get_instance" do
+ get collection_url(:instances) + '/' + instance_id
+ end
+ last_response.status.must_equal 200 # HTTP_OK
+ (xml_response/'instance').first[:id].must_equal instance_id
+ (xml_response/'instance/image').first[:id].must_equal image_id
+ 10.times do |i|
+ VCR.use_cassette "#{__name__}_pool_#{i}_instance" do
+ get collection_url(:instances) + '/' + instance_id
+ end
+ break if (xml_response/'instance/state').text == 'RUNNING'
+ sleep(10)
+ end
+ (xml_response/'instance/state').text.must_equal 'RUNNING'
+ (xml_response/'instance/hardware_profile').first[:id].must_equal hwp_id
+ # Delete created instance
+ VCR.use_cassette "#{__name__}_delete_instance" do
+ post collection_url(:instances) + '/' + instance_id + '/stop'
+ end
+ last_response.status.must_equal 202 # HTTP_NO_CONTENT
+ end
+
+end
diff --git a/server/tests/drivers/ec2/keys_test.rb b/server/tests/drivers/ec2/keys_test.rb
new file mode 100644
index 0000000..814de38
--- /dev/null
+++ b/server/tests/drivers/ec2/keys_test.rb
@@ -0,0 +1,181 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/ec2/common'
+
+describe 'Deltacloud API Keys' do
+
+ before do
+ Timecop.freeze(FREEZED_TIME)
+ VCR.insert_cassette __name__
+ end
+
+ after do
+ VCR.eject_cassette
+ end
+
+ include Deltacloud::Test
+
+ it 'must advertise have the keys collection in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link[@rel=keys]').wont_be_empty
+ end
+
+ it 'must require authentication to access the "key" collection' do
+ get collection_url(:keys)
+ last_response.status.must_equal 401
+ end
+
+ it 'should respond with HTTP_OK when accessing the :keys collection with authentication' do
+ auth_as_mock
+ get collection_url(:keys)
+ last_response.status.must_equal 200
+ end
+
+ it 'should support the JSON media type' do
+ auth_as_mock
+ header 'Accept', 'application/json'
+ get collection_url(:keys)
+ last_response.status.must_equal 200
+ last_response.headers['Content-Type'].must_equal 'application/json'
+ end
+
+ it 'must include the ETag in HTTP headers' do
+ auth_as_mock
+ get collection_url(:keys)
+ last_response.headers['ETag'].wont_be_nil
+ end
+
+ it 'must have the "keys" element on top level' do
+ auth_as_mock
+ get collection_url(:keys)
+ xml_response.root.name.must_equal 'keys'
+ end
+
+ it 'must have some "key" elements inside "keys"' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').wont_be_empty
+ end
+
+ it 'must tell the kind of "key" elements inside "keys"' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').each do |k|
+ k[:type].must_match /(key|password)/
+ end
+ end
+
+ it 'must provide the :id attribute for each key in collection' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').each do |r|
+ r[:id].wont_be_nil
+ end
+ end
+
+ it 'must include the :href attribute for each "key" element in collection' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').each do |r|
+ r[:href].wont_be_nil
+ end
+ end
+
+ it 'must use the absolute URL in each :href attribute' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').each do |r|
+ r[:href].must_match /^http/
+ end
+ end
+
+ it 'must have the URL ending with the :id of the key' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').each do |r|
+ r[:href].must_match /#{r[:id]}$/
+ end
+ end
+
+ it 'must return the list of valid parameters for the :index action' do
+ auth_as_mock
+ options collection_url(:keys) + '/index'
+ last_response.headers['Allow'].wont_be_nil
+ end
+
+ it 'must have the "name" element defined for each key in collection' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').each do |r|
+ (r/'name').wont_be_empty
+ end
+ end
+
+
+ it 'must return the full "key" when following the URL in key element' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').each do |r|
+ get collection_url(:keys) + '/' + r[:id]
+ last_response.status.must_equal 200
+ end
+ end
+
+ it 'must have the "name" element for the key and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').each do |r|
+ VCR.use_cassette "#{__name__}_key_#{r[:id]}" do
+ get collection_url(:keys) + '/' + r[:id]
+ end
+ (xml_response/'name').wont_be_empty
+ (xml_response/'name').first.text.must_equal((r/'name').first.text)
+ end
+ end
+
+ it 'must have the "name" element for the key and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').each do |r|
+ VCR.use_cassette "#{__name__}_key_#{r[:id]}" do
+ get collection_url(:keys) + '/' + r[:id]
+ end
+ (xml_response/'state').wont_be_empty
+ (xml_response/'state').first.text.must_equal((r/'state').first.text)
+ end
+ end
+
+ it 'should advertise the list of actions that can be executed for each key' do
+ auth_as_mock
+ get collection_url(:keys)
+ (xml_response/'keys/key').each do |r|
+ VCR.use_cassette "#{__name__}_key_#{r[:id]}" do
+ get collection_url(:keys) + '/' + r[:id]
+ end
+ (xml_response/'actions/link').wont_be_empty
+ (xml_response/'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 a new key and then remove it' do
+ auth_as_mock
+ key_name = Time.now.to_i.to_s
+ post collection_url(:keys), {
+ :name => 'test_key_'+key_name
+ }
+ last_response.status.must_equal 201 # HTTP_CREATED
+ VCR.use_cassette "#{__name__}_key_#{key_name}" do
+ get collection_url(:keys) + '/' + 'test_key_'+key_name
+ end
+ last_response.status.must_equal 200 # HTTP_OK
+ VCR.use_cassette "#{__name__}_delete_key_#{key_name}" do
+ delete collection_url(:keys) + '/' + 'test_key_'+key_name
+ end
+ last_response.status.must_equal 204 # HTTP_NO_CONTENT
+ end
+
+end
diff --git a/server/tests/drivers/ec2/realms_test.rb b/server/tests/drivers/ec2/realms_test.rb
new file mode 100644
index 0000000..8e8b325
--- /dev/null
+++ b/server/tests/drivers/ec2/realms_test.rb
@@ -0,0 +1,146 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/ec2/common'
+
+describe 'Deltacloud API Realms' do
+ before do
+ Timecop.freeze(FREEZED_TIME)
+ VCR.insert_cassette __name__
+ end
+
+ after do
+ VCR.eject_cassette
+ end
+
+ include Deltacloud::Test
+
+ it 'must advertise have the realms collection in API entrypoint' do
+ get Deltacloud[:root_url]
+ (xml_response/'api/link[@rel=realms]').wont_be_empty
+ end
+
+ it 'must require authentication to access the "realm" collection' do
+ get collection_url(:realms)
+ last_response.status.must_equal 401
+ end
+
+ it 'should respond with HTTP_OK when accessing the :realms collection with authentication' do
+ auth_as_mock
+ get collection_url(:realms)
+ last_response.status.must_equal 200
+ end
+
+ it 'should support the JSON media type' do
+ auth_as_mock
+ header 'Accept', 'application/json'
+ get collection_url(:realms)
+ last_response.status.must_equal 200
+ last_response.headers['Content-Type'].must_equal 'application/json'
+ end
+
+ it 'must include the ETag in HTTP headers' do
+ auth_as_mock
+ get collection_url(:realms)
+ last_response.headers['ETag'].wont_be_nil
+ end
+
+ it 'must have the "realms" element on top level' do
+ auth_as_mock
+ get collection_url(:realms)
+ xml_response.root.name.must_equal 'realms'
+ end
+
+ it 'must have some "realm" elements inside "realms"' do
+ auth_as_mock
+ get collection_url(:realms)
+ (xml_response/'realms/realm').wont_be_empty
+ end
+
+ it 'must provide the :id attribute for each realm in collection' do
+ auth_as_mock
+ get collection_url(:realms)
+ (xml_response/'realms/realm').each do |r|
+ r[:id].wont_be_nil
+ end
+ end
+
+ it 'must include the :href attribute for each "realm" element in collection' do
+ auth_as_mock
+ get collection_url(:realms)
+ (xml_response/'realms/realm').each do |r|
+ r[:href].wont_be_nil
+ end
+ end
+
+ it 'must use the absolute URL in each :href attribute' do
+ auth_as_mock
+ get collection_url(:realms)
+ (xml_response/'realms/realm').each do |r|
+ r[:href].must_match /^http/
+ end
+ end
+
+ it 'must have the URL ending with the :id of the realm' do
+ auth_as_mock
+ get collection_url(:realms)
+ (xml_response/'realms/realm').each do |r|
+ r[:href].must_match /#{r[:id]}$/
+ end
+ end
+
+ it 'must return the list of valid parameters for the :index action' do
+ auth_as_mock
+ options collection_url(:realms) + '/index'
+ last_response.headers['Allow'].wont_be_nil
+ end
+
+ it 'must have the "name" element defined for each realm in collection' do
+ auth_as_mock
+ get collection_url(:realms)
+ (xml_response/'realms/realm').each do |r|
+ (r/'name').wont_be_empty
+ end
+ end
+
+ it 'must have the "state" element defined for each realm in collection' do
+ auth_as_mock
+ get collection_url(:realms)
+ (xml_response/'realms/realm').each do |r|
+ (r/'state').wont_be_empty
+ end
+ end
+ it 'must return the full "realm" when following the URL in realm element' do
+ auth_as_mock
+ get collection_url(:realms)
+ (xml_response/'realms/realm').each do |r|
+ VCR.use_cassette "#{__name__}_realm_id" do
+ get collection_url(:realms) + '/' + r[:id]
+ end
+ last_response.status.must_equal 200
+ end
+ end
+
+ it 'must have the "name" element for the realm and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:realms)
+ (xml_response/'realms/realm').each do |r|
+ VCR.use_cassette "#{__name__}_realm_#{r[:id]}" do
+ get collection_url(:realms) + '/' + r[:id]
+ end
+ (xml_response/'name').wont_be_empty
+ (xml_response/'name').first.text.must_equal((r/'name').first.text)
+ end
+ end
+
+ it 'must have the "state" element for the realm and it should match with the one in collection' do
+ auth_as_mock
+ get collection_url(:realms)
+ (xml_response/'realms/realm').each do |r|
+ VCR.use_cassette "#{__name__}_realm_r[:id]" do
+ get collection_url(:realms) + '/' + r[:id]
+ end
+ (xml_response/'state').wont_be_empty
+ (xml_response/'state').first.text.must_equal((r/'state').first.text)
+ end
+ end
+
+end
--
1.7.10.2
Re: [PATCH core 1/2] Ec2: Added minitest suite for EC2 driver using
VCR recording
Posted by Michal Fojtik <mf...@redhat.com>.
On 05/24/12, mfojtik@redhat.com wrote:
The second part of this patch is here:
http://omicron.mifo.sk/0002-Ec2-Added-VCR-cassette-required-to-run-Ec2-minitest.patch.gz
It's pretty large and ezmlm refused to sent it to list ;-)
-- Michal
> From: Michal Fojtik <mf...@redhat.com>
>
>
> Signed-off-by: Michal fojtik <mf...@redhat.com>
> ---
> server/Rakefile | 2 +-
> server/tests/drivers/ec2/api_test.rb | 128 +++++++
> server/tests/drivers/ec2/common.rb | 69 ++++
> server/tests/drivers/ec2/drivers_test.rb | 120 +++++++
> server/tests/drivers/ec2/hardware_profiles_test.rb | 224 ++++++++++++
> server/tests/drivers/ec2/images_test.rb | 230 +++++++++++++
> server/tests/drivers/ec2/instances_test.rb | 356 ++++++++++++++++++++
> server/tests/drivers/ec2/keys_test.rb | 181 ++++++++++
> server/tests/drivers/ec2/realms_test.rb | 146 ++++++++
> 9 files changed, 1455 insertions(+), 1 deletion(-)
> create mode 100644 server/tests/drivers/ec2/api_test.rb
> create mode 100644 server/tests/drivers/ec2/common.rb
> create mode 100644 server/tests/drivers/ec2/drivers_test.rb
> create mode 100644 server/tests/drivers/ec2/hardware_profiles_test.rb
> create mode 100644 server/tests/drivers/ec2/images_test.rb
> create mode 100644 server/tests/drivers/ec2/instances_test.rb
> create mode 100644 server/tests/drivers/ec2/keys_test.rb
> create mode 100644 server/tests/drivers/ec2/realms_test.rb
>
> diff --git a/server/Rakefile b/server/Rakefile
> index 8223e5e..ded7d8b 100644
> --- a/server/Rakefile
> +++ b/server/Rakefile
> @@ -226,7 +226,7 @@ end
>
> namespace :test do
>
> - %w(mock rackspace rhevm openstack google fgcp).each do |driver|
> + %w(mock rackspace rhevm openstack google fgcp ec2).each do |driver|
> desc "Run #{driver} unit tests"
> Rake::TestTask.new(driver) { |t|
> t.test_files = FileList.new("tests/drivers/#{driver}/*_test.rb")
> diff --git a/server/tests/drivers/ec2/api_test.rb b/server/tests/drivers/ec2/api_test.rb
> new file mode 100644
> index 0000000..a5b2333
> --- /dev/null
> +++ b/server/tests/drivers/ec2/api_test.rb
> @@ -0,0 +1,128 @@
> +$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
> +require 'tests/drivers/ec2/common'
> +
> +describe 'Deltacloud API' do
> +
> + before do
> + Timecop.freeze(FREEZED_TIME)
> + VCR.insert_cassette __name__
> + end
> +
> + after do
> + VCR.eject_cassette
> + end
> +
> + include Deltacloud::Test
> +
> + it 'return HTTP_OK when accessing API entrypoint' do
> + get Deltacloud[:root_url]
> + last_response.status.must_equal 200
> + end
> +
> + it 'advertise the current driver in API entrypoint' do
> + get Deltacloud[:root_url]
> + xml_response.root[:driver].must_equal ENV['API_DRIVER']
> + end
> +
> + it 'advertise the current API version in API entrypoint' do
> + get Deltacloud[:root_url]
> + xml_response.root[:version].must_equal Deltacloud[:version]
> + end
> +
> + it 'advertise the current API version in HTTP headers' do
> + get Deltacloud[:root_url]
> + last_response.headers['Server'].must_equal "Apache-Deltacloud/#{Deltacloud[:version]}"
> + end
> +
> + it 'must include the ETag in HTTP headers' do
> + get Deltacloud[:root_url]
> + last_response.headers['ETag'].wont_be_nil
> + end
> +
> + it 'advertise collections in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link').wont_be_empty
> + end
> +
> + it 'include the :href and :rel attribute for each collection in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link').each do |collection|
> + collection[:href].wont_be_nil
> + collection[:rel].wont_be_nil
> + end
> + end
> +
> + it 'uses the absolute URI in the :href attribute for each collection in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link').each do |collection|
> + collection[:href].must_match /^http/
> + end
> + end
> +
> + it 'advertise features for some collections in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link/feature').wont_be_empty
> + end
> +
> + it 'advertise the name of the feature for some collections in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link/feature').each do |f|
> + f[:name].wont_be_nil
> + end
> + end
> +
> + it 'must change the media type from XML to JSON using Accept headers' do
> + header 'Accept', 'application/json'
> + get Deltacloud[:root_url]
> + last_response.headers['Content-Type'].must_equal 'application/json'
> + end
> +
> + it 'must change the media type to JSON using the "?format" parameter in URL' do
> + get Deltacloud[:root_url], { :format => 'json' }
> + last_response.headers['Content-Type'].must_equal 'application/json'
> + end
> +
> + it 'must change the driver when using X-Deltacloud-Driver HTTP header' do
> + header 'X-Deltacloud-Driver', 'ec2'
> + get Deltacloud[:root_url]
> + xml_response.root[:driver].must_equal 'ec2'
> + header 'X-Deltacloud-Driver', 'mock'
> + get Deltacloud[:root_url]
> + xml_response.root[:driver].must_equal 'mock'
> + end
> +
> + it 'must change the features when driver is swapped using HTTP headers' do
> + header 'X-Deltacloud-Driver', 'ec2'
> + get Deltacloud[:root_url]
> + # The 'user_name' feature is not supported currently for the EC2 driver
> + (xml_response/'api/link/feature').map { |f| f[:name] }.wont_include 'user_name'
> + header 'X-Deltacloud-Driver', 'mock'
> + get Deltacloud[:root_url]
> + # But it's supported in Mock driver
> + (xml_response/'api/link/feature').map { |f| f[:name] }.must_include 'user_name'
> + end
> +
> + it 'must re-validate the driver credentials when using "?force_auth" parameter in URL' do
> + get Deltacloud[:root_url], { :force_auth => '1' }
> + last_response.status.must_equal 401
> + auth_as_mock
> + get Deltacloud[:root_url], { :force_auth => '1' }
> + last_response.status.must_equal 200
> + end
> +
> + it 'must change the API PROVIDER using the /api;provider matrix parameter in URI' do
> + get Deltacloud[:root_url] + ';provider=test1'
> + xml_response.root[:provider].wont_be_nil
> + xml_response.root[:provider].must_equal 'test1'
> + get Deltacloud[:root_url] + ';provider=test2'
> + xml_response.root[:provider].must_equal 'test2'
> + end
> +
> + it 'must change the API DRIVER using the /api;driver matrix parameter in URI' do
> + get Deltacloud[:root_url] + ';driver=ec2'
> + xml_response.root[:driver].must_equal 'ec2'
> + get Deltacloud[:root_url] + ';driver=mock'
> + xml_response.root[:driver].must_equal 'mock'
> + end
> +
> +end
> diff --git a/server/tests/drivers/ec2/common.rb b/server/tests/drivers/ec2/common.rb
> new file mode 100644
> index 0000000..83f315b
> --- /dev/null
> +++ b/server/tests/drivers/ec2/common.rb
> @@ -0,0 +1,69 @@
> +ENV['API_DRIVER'] = 'ec2'
> +ENV['API_USERNAME'] = 'AKIAI77KNAA7ZXRLL7GQ'
> +ENV['API_PASSWORD'] = 'idJ9vktNaDWAK0LWVVE/526ONvJmTl2Crto/s8Ok'
> +ENV['RACK_ENV'] = 'test'
> +
> +load File.join(File.dirname(__FILE__), '..', '..', '..', 'lib', 'deltacloud_rack.rb')
> +
> +Deltacloud::configure do |server|
> + server.root_url '/api'
> + server.version '0.5.0'
> + server.klass 'Deltacloud::API'
> +end.require_frontend!
> +
> +require 'minitest/autorun'
> +require 'rack/test'
> +require 'nokogiri'
> +require 'json'
> +require 'pp'
> +require 'vcr'
> +require 'timecop'
> +
> +VCR.configure do |c|
> + c.cassette_library_dir = File.join(File.dirname(__FILE__), 'fixtures')
> + c.hook_into :webmock
> + c.default_cassette_options = { :record => :new_episodes }
> + #c.default_cassette_options = { :record => :none }
> +end
> +
> +# Let's set time that timecop will use to freeze
> +# Time.now will then return this time instead of 'real' system time
> +
> +FREEZED_TIME = Time.local(2012, 5, 24, 18, 10, 0).freeze
> +
> +module Deltacloud
> + module Test
> + include Rack::Test::Methods
> +
> + def included?(sub)
> + sub.class_eval do
> + before do
> + header 'Accept', 'application/xml'
> + end
> + end
> + end
> +
> + def xml_response
> + Nokogiri::XML(last_response.body)
> + end
> +
> + def auth_as_mock
> + authorize ENV['API_USERNAME'], ENV['API_PASSWORD']
> + end
> +
> + def collection_url(collection)
> + [Deltacloud[:root_url], collection.to_s].join('/')
> + end
> +
> + def app
> + Rack::Builder.new {
> + map '/' do
> + Timecop.freeze(FREEZED_TIME) do
> + use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
> + run Rack::Cascade.new([Deltacloud::API])
> + end
> + end
> + }
> + end
> + end
> +end
> diff --git a/server/tests/drivers/ec2/drivers_test.rb b/server/tests/drivers/ec2/drivers_test.rb
> new file mode 100644
> index 0000000..26adc7b
> --- /dev/null
> +++ b/server/tests/drivers/ec2/drivers_test.rb
> @@ -0,0 +1,120 @@
> +$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
> +require 'tests/drivers/ec2/common'
> +
> +describe 'Deltacloud API drivers' do
> + include Deltacloud::Test
> + before do
> + Timecop.freeze(FREEZED_TIME)
> + VCR.insert_cassette __name__
> + end
> +
> + after do
> + VCR.eject_cassette
> + end
> +
> + it 'must advertise have the drivers collection in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link[@rel=drivers]').wont_be_empty
> + end
> +
> + it 'must not require authentication to access the "driver" collection' do
> + get collection_url(:drivers)
> + last_response.status.must_equal 200
> + end
> +
> + it 'should respond with HTTP_OK when accessing the :drivers collection with authentication' do
> + get collection_url(:drivers)
> + last_response.status.must_equal 200
> + end
> +
> + it 'should support the JSON media type' do
> + header 'Accept', 'application/json'
> + get collection_url(:drivers)
> + last_response.status.must_equal 200
> + last_response.headers['Content-Type'].must_equal 'application/json'
> + end
> +
> + it 'must include the ETag in HTTP headers' do
> + get collection_url(:drivers)
> + last_response.headers['ETag'].wont_be_nil
> + end
> +
> + it 'must have the "drivers" element on top level' do
> + get collection_url(:drivers)
> + xml_response.root.name.must_equal 'drivers'
> + end
> +
> + it 'must have some "driver" elements inside "drivers"' do
> + get collection_url(:drivers)
> + (xml_response/'drivers/driver').wont_be_empty
> + end
> +
> + it 'must provide the :id attribute for each driver in collection' do
> + get collection_url(:drivers)
> + (xml_response/'drivers/driver').each do |r|
> + r[:id].wont_be_nil
> + end
> + end
> +
> + it 'must include the :href attribute for each "driver" element in collection' do
> + get collection_url(:drivers)
> + (xml_response/'drivers/driver').each do |r|
> + r[:href].wont_be_nil
> + end
> + end
> +
> + it 'must use the absolute URL in each :href attribute' do
> + get collection_url(:drivers)
> + (xml_response/'drivers/driver').each do |r|
> + r[:href].must_match /^http/
> + end
> + end
> +
> + it 'must have the URL ending with the :id of the driver' do
> + get collection_url(:drivers)
> + (xml_response/'drivers/driver').each do |r|
> + r[:href].must_match /#{r[:id]}$/
> + end
> + end
> +
> + it 'must return the list of valid parameters for the :index action' do
> + options collection_url(:drivers) + '/index'
> + last_response.headers['Allow'].wont_be_nil
> + end
> +
> + it 'must have the "name" element defined for each driver in collection' do
> + get collection_url(:drivers)
> + (xml_response/'drivers/driver').each do |r|
> + (r/'name').wont_be_nil
> + end
> + end
> +
> +
> + it 'must return the full "driver" when following the URL in driver element' do
> + auth_as_mock
> + get collection_url(:drivers)
> + (xml_response/'drivers/driver').each do |r|
> + get collection_url(:drivers) + '/' + r[:id]
> + last_response.status.must_equal 200
> + end
> + end
> +
> + it 'must have the "name" element for the driver and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:drivers)
> + (xml_response/'drivers/driver').each do |r|
> + r[:id].wont_be_nil
> + get collection_url(:drivers) + '/' + r[:id]
> + (xml_response/'name').wont_be_empty
> + (xml_response/'name').first.text.must_equal((r/'name').first.text)
> + end
> + end
> +
> + it 'should advertise available providers for some drivers' do
> + get collection_url(:drivers)
> + (xml_response/'drivers/driver/provider').each do |p|
> + p[:id].wont_be_nil
> + end
> + end
> +
> +end
> diff --git a/server/tests/drivers/ec2/hardware_profiles_test.rb b/server/tests/drivers/ec2/hardware_profiles_test.rb
> new file mode 100644
> index 0000000..efafa72
> --- /dev/null
> +++ b/server/tests/drivers/ec2/hardware_profiles_test.rb
> @@ -0,0 +1,224 @@
> +$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
> +require 'tests/drivers/ec2/common'
> +
> +describe 'Deltacloud API Hardware Profiles' do
> + include Deltacloud::Test
> +
> + it 'must advertise have the hardware_profiles collection in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link[@rel=hardware_profiles]').wont_be_empty
> + end
> +
> + it 'should respond with HTTP_OK when accessing the :hardware_profiles collection with authentication' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + last_response.status.must_equal 200
> + end
> +
> + it 'should support the JSON media type' do
> + auth_as_mock
> + header 'Accept', 'application/json'
> + get collection_url(:hardware_profiles)
> + last_response.status.must_equal 200
> + last_response.headers['Content-Type'].must_equal 'application/json'
> + end
> +
> + it 'must include the ETag in HTTP headers' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + last_response.headers['ETag'].wont_be_nil
> + end
> +
> + it 'must have the "hardware_profiles" element on top level' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + xml_response.root.name.must_equal 'hardware_profiles'
> + end
> +
> + it 'must have some "hardware_profile" elements inside "hardware_profiles"' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').wont_be_empty
> + end
> +
> + it 'must provide the :id attribute for each hardware_profile in collection' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + r[:id].wont_be_nil
> + end
> + end
> +
> + it 'must include the :href attribute for each "hardware_profile" element in collection' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + r[:href].wont_be_nil
> + end
> + end
> +
> + it 'must use the absolute URL in each :href attribute' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + r[:href].must_match /^http/
> + end
> + end
> +
> + it 'must have the URL ending with the :id of the hardware_profile' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + r[:href].must_match /#{r[:id]}$/
> + end
> + end
> +
> + it 'must return the list of valid parameters for the :index action' do
> + auth_as_mock
> + options collection_url(:hardware_profiles) + '/index'
> + last_response.headers['Allow'].wont_be_nil
> + end
> +
> + it 'must have the "name" element defined for each hardware_profile in collection' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + (r/'name').wont_be_empty
> + end
> + end
> +
> + it 'should have the "property" element defined if not the opaque hardware_profile' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + next if r[:id] == 'opaque'
> + (r/'property').wont_be_empty
> + end
> + end
> +
> + it 'must define the :kind attribute for each "property" ' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + next if r[:id] == 'opaque'
> + (r/'property').each { |p| p[:kind].wont_be_nil }
> + end
> + end
> +
> + it 'must define the :name attribute for each "property" ' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + next if r[:id] == 'opaque'
> + (r/'property').each { |p| p[:name].wont_be_nil }
> + end
> + end
> +
> + it 'must define the :unit attribute for each "property" ' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + next if r[:id] == 'opaque'
> + (r/'property').each { |p| p[:unit].wont_be_nil }
> + end
> + end
> +
> + it 'must define the :value attribute for each "property" ' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + next if r[:id] == 'opaque'
> + (r/'property').each { |p| p[:value].wont_be_nil }
> + end
> + end
> +
> + it 'must define the "param" element if property kind is not "fixed"' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + next if r[:id] == 'opaque'
> + (r/'property').each do |p|
> + next if p[:kind] == 'fixed'
> + (p/'param').wont_be_empty
> + (p/'param').size.must_equal 1
> + (p/'param').first[:href].wont_be_nil
> + (p/'param').first[:href].must_match /^http/
> + (p/'param').first[:method].wont_be_nil
> + (p/'param').first[:name].wont_be_nil
> + (p/'param').first[:operation].wont_be_nil
> + end
> + end
> + end
> +
> + it 'must provide the list of valid values when the property is defined as "enum"' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + next if r[:id] == 'opaque'
> + (r/'property').each do |p|
> + next if p[:kind] != 'enum'
> + (p/'enum/entry').wont_be_empty
> + (p/'enum/entry').each { |e| e[:value].wont_be_nil }
> + end
> + end
> + end
> +
> + it 'must provide the range of valid values when the property is defined as "range"' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + next if r[:id] == 'opaque'
> + (r/'property').each do |p|
> + next if p[:kind] != 'range'
> + (p/'range').wont_be_empty
> + (p/'range').size.must_equal 1
> + (p/'range').first[:first].wont_be_nil
> + (p/'range').first[:last].wont_be_nil
> + end
> + end
> + end
> +
> + it 'must provide the default value within the range if property defined as "range"' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + next if r[:id] == 'opaque'
> + (r/'property').each do |p|
> + next if p[:kind] != 'range'
> + ((p/'range').first[:first].to_i..(p/'range').first[:last].to_i).include?(p[:value].to_i).must_equal true
> + end
> + end
> + end
> +
> + it 'must provide the default value that is included in enum list if property defined as "enum"' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + next if r[:id] == 'opaque'
> + (r/'property').each do |p|
> + next if p[:kind] != 'enum'
> + (p/'enum/entry').map { |e| e[:value] }.include?(p[:value]).must_equal true
> + end
> + end
> + end
> +
> + it 'must return the full "hardware_profile" when following the URL in hardware_profile element' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + get collection_url(:hardware_profiles) + '/' + r[:id]
> + last_response.status.must_equal 200
> + end
> + end
> +
> + it 'must have the "name" element for the hardware_profile and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:hardware_profiles)
> + (xml_response/'hardware_profiles/hardware_profile').each do |r|
> + get collection_url(:hardware_profiles) + '/' + r[:id]
> + (xml_response/'name').wont_be_empty
> + (xml_response/'name').first.text.must_equal((r/'name').first.text)
> + end
> + end
> +
> +end
> diff --git a/server/tests/drivers/ec2/images_test.rb b/server/tests/drivers/ec2/images_test.rb
> new file mode 100644
> index 0000000..34884fa
> --- /dev/null
> +++ b/server/tests/drivers/ec2/images_test.rb
> @@ -0,0 +1,230 @@
> +$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
> +require 'tests/drivers/ec2/common'
> +
> +describe 'Deltacloud API Images' do
> + before do
> + Timecop.freeze(FREEZED_TIME)
> + VCR.insert_cassette __name__
> + end
> +
> + after do
> + VCR.eject_cassette
> + end
> +
> + include Deltacloud::Test
> +
> + it 'must advertise have the images collection in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link[@rel=images]').wont_be_empty
> + end
> +
> + it 'must require authentication to access the "image" collection' do
> + get collection_url(:images)
> + last_response.status.must_equal 401
> + end
> +
> + it 'should respond with HTTP_OK when accessing the :images collection with authentication' do
> + auth_as_mock
> + get collection_url(:images)
> + last_response.status.must_equal 200
> + end
> +
> + it 'should support the JSON media type' do
> + auth_as_mock
> + header 'Accept', 'application/json'
> + get collection_url(:images)
> + last_response.status.must_equal 200
> + last_response.headers['Content-Type'].must_equal 'application/json'
> + end
> +
> + it 'must include the ETag in HTTP headers' do
> + auth_as_mock
> + get collection_url(:images)
> + last_response.headers['ETag'].wont_be_nil
> + end
> +
> + it 'must have the "images" element on top level' do
> + auth_as_mock
> + get collection_url(:images)
> + xml_response.root.name.must_equal 'images'
> + end
> +
> + it 'must have some "image" elements inside "images"' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').wont_be_empty
> + end
> +
> + it 'must provide the :id attribute for each image in collection' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').each do |r|
> + r[:id].wont_be_nil
> + end
> + end
> +
> + it 'must include the :href attribute for each "image" element in collection' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').each do |r|
> + r[:href].wont_be_nil
> + end
> + end
> +
> + it 'must use the absolute URL in each :href attribute' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').each do |r|
> + r[:href].must_match /^http/
> + end
> + end
> +
> + it 'must have the URL ending with the :id of the image' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').each do |r|
> + r[:href].must_match /#{r[:id]}$/
> + end
> + end
> +
> + it 'must return the list of valid parameters for the :index action' do
> + auth_as_mock
> + options collection_url(:images) + '/index'
> + last_response.headers['Allow'].wont_be_nil
> + end
> +
> + it 'must have the "name" element defined for each image in collection' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').each do |r|
> + (r/'name').wont_be_empty
> + end
> + end
> +
> + it 'must have the "state" element defined for each image in collection' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').each do |r|
> + (r/'state').wont_be_empty
> + end
> + end
> +
> + it 'must return the full "image" when following the URL in image element' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').wont_be_empty
> + (xml_response/'images/image')[0..10].each do |r|
> + VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
> + get collection_url(:images) + '/' + r[:id]
> + end
> + last_response.status.must_equal 200
> + end
> + end
> +
> + it 'must have the "name" element for the image and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').wont_be_empty
> + (xml_response/'images/image')[0..10].each do |r|
> + VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
> + get collection_url(:images) + '/' + r[:id]
> + end
> + (xml_response/'name').wont_be_empty
> + (xml_response/'name').first.text.must_equal((r/'name').first.text)
> + end
> + end
> +
> + it 'must have the "name" element for the image and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').wont_be_empty
> + (xml_response/'images/image')[0..10].each do |r|
> + VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
> + get collection_url(:images) + '/' + r[:id]
> + end
> + (xml_response/'state').wont_be_empty
> + (xml_response/'state').first.text.must_equal((r/'state').first.text)
> + end
> + end
> +
> + it 'should have the "owner_id" element for each image' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').wont_be_empty
> + (xml_response/'images/image')[0..10].each do |r|
> + VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
> + get collection_url(:images) + '/' + r[:id]
> + end
> + (xml_response/'owner_id').wont_be_empty
> + end
> + end
> +
> + it 'should have the "description" element for each image' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').wont_be_empty
> + (xml_response/'images/image')[0..10].each do |r|
> + VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
> + get collection_url(:images) + '/' + r[:id]
> + end
> + (xml_response/'description').wont_be_empty
> + end
> + end
> +
> + it 'should have the "architecture" element for each image' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').wont_be_empty
> + (xml_response/'images/image')[0..10].each do |r|
> + VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
> + get collection_url(:images) + '/' + r[:id]
> + end
> + (xml_response/'architecture').wont_be_empty
> + end
> + end
> +
> + it 'should include the list of compatible hardware_profiles for each image' do
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').wont_be_empty
> + (xml_response/'images/image')[0..10].each do |r|
> + VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
> + get collection_url(:images) + '/' + r[:id]
> + end
> + (xml_response/'hardware_profiles/hardware_profile').wont_be_empty
> + (xml_response/'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
> + auth_as_mock
> + get collection_url(:images)
> + (xml_response/'images/image').wont_be_empty
> + (xml_response/'images/image')[0..10].each do |r|
> + VCR.use_cassette "#{__name__}_image_#{r[:id]}" do
> + get collection_url(:images) + '/' + r[:id]
> + end
> + (xml_response/'actions/link').wont_be_empty
> + (xml_response/'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 give client HTML form to create new image' do
> + auth_as_mock
> + header 'Accept', 'text/html'
> + get collection_url(:images) + '/new'
> + last_response.status.must_equal 200
> + end
> +
> +end
> diff --git a/server/tests/drivers/ec2/instances_test.rb b/server/tests/drivers/ec2/instances_test.rb
> new file mode 100644
> index 0000000..e0388f0
> --- /dev/null
> +++ b/server/tests/drivers/ec2/instances_test.rb
> @@ -0,0 +1,356 @@
> +$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
> +require 'tests/drivers/ec2/common'
> +
> +describe 'Deltacloud API instances' do
> + include Deltacloud::Test
> +
> + before do
> + Timecop.freeze(FREEZED_TIME)
> + VCR.insert_cassette __name__
> + end
> +
> + after do
> + VCR.eject_cassette
> + end
> +
> + it 'must advertise have the instances collection in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link[@rel=instances]').wont_be_empty
> + end
> +
> +
> + it 'must require authentication to access the "instance" collection' do
> + get collection_url(:instances)
> + last_response.status.must_equal 401
> + end
> +
> + it 'should respond with HTTP_OK when accessing the :instances collection with authentication' do
> + auth_as_mock
> + get collection_url(:instances)
> + last_response.status.must_equal 200
> + end
> +
> + it 'should support the JSON media type' do
> + auth_as_mock
> + header 'Accept', 'application/json'
> + get collection_url(:instances)
> + last_response.status.must_equal 200
> + last_response.headers['Content-Type'].must_equal 'application/json'
> + end
> +
> + it 'must include the ETag in HTTP headers' do
> + auth_as_mock
> + get collection_url(:instances)
> + last_response.headers['ETag'].wont_be_nil
> + end
> +
> + it 'must have the "instances" element on top level' do
> + auth_as_mock
> + get collection_url(:instances)
> + xml_response.root.name.must_equal 'instances'
> + end
> +
> + it 'must have some "instance" elements inside "instances"' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').wont_be_empty
> + end
> +
> + it 'must provide the :id attribute for each instance in collection' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + r[:id].wont_be_nil
> + end
> + end
> +
> + it 'must include the :href attribute for each "instance" element in collection' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + r[:href].wont_be_nil
> + end
> + end
> +
> + it 'must use the absolute URL in each :href attribute' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + r[:href].must_match /^http/
> + end
> + end
> +
> + it 'must have the URL ending with the :id of the instance' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + r[:href].must_match /#{r[:id]}$/
> + end
> + end
> +
> + it 'must return the list of valid parameters for the :index action' do
> + auth_as_mock
> + options collection_url(:instances) + '/index'
> + last_response.headers['Allow'].wont_be_nil
> + end
> +
> + it 'must have the "name" element defined for each instance in collection' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + (r/'name').wont_be_empty
> + end
> + end
> +
> + it 'must have the "state" element defined for each instance in collection' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + (r/'state').wont_be_empty
> + (r/'state').first.must_match /(RUNNING|STOPPED|PENDING)/
> + end
> + end
> +
> +
> + it 'must return the full "instance" when following the URL in instance element' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
> + get collection_url(:instances) + '/' + r[:id]
> + end
> + last_response.status.must_equal 200
> + end
> + end
> +
> +
> + it 'must have the "name" element for the instance and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
> + get collection_url(:instances) + '/' + r[:id]
> + end
> + (xml_response/'name').wont_be_empty
> + (xml_response/'name').first.text.must_equal((r/'name').first.text)
> + end
> + end
> +
> + it 'must have the "name" element for the instance and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
> + get collection_url(:instances) + '/' + r[:id]
> + end
> + (xml_response/'state').wont_be_empty
> + (xml_response/'state').first.text.must_equal((r/'state').first.text)
> + end
> + end
> +
> + it 'must have the "owner_id" element for the instance and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
> + get collection_url(:instances) + '/' + r[:id]
> + end
> + (xml_response/'owner_id').wont_be_empty
> + (xml_response/'owner_id').first.text.must_equal((r/'owner_id').first.text)
> + end
> + end
> +
> + it 'must link to the realm that was used to during instance creation' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
> + get collection_url(:instances) + '/' + r[:id]
> + end
> + (xml_response/'realm').wont_be_empty
> + (xml_response/'realm').size.must_equal 1
> + (xml_response/'realm').first[:id].wont_be_nil
> + (xml_response/'realm').first[:href].wont_be_nil
> + (xml_response/'realm').first[:href].must_match /\/#{(xml_response/'realm').first[:id]}$/
> + end
> + end
> +
> + it 'must link to the image that was used to during instance creation' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
> + get collection_url(:instances) + '/' + r[:id]
> + end
> + (xml_response/'image').wont_be_empty
> + (xml_response/'image').size.must_equal 1
> + (xml_response/'image').first[:id].wont_be_nil
> + (xml_response/'image').first[:href].wont_be_nil
> + (xml_response/'image').first[:href].must_match /\/#{(xml_response/'image').first[:id]}$/
> + end
> + end
> +
> + it 'must link to the hardware_profile that was used to during instance creation' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
> + get collection_url(:instances) + '/' + r[:id]
> + end
> + (xml_response/'hardware_profile').wont_be_empty
> + (xml_response/'hardware_profile').size.must_equal 1
> + (xml_response/'hardware_profile').first[:id].wont_be_nil
> + (xml_response/'hardware_profile').first[:href].wont_be_nil
> + (xml_response/'hardware_profile').first[:href].must_match /\/#{(xml_response/'hardware_profile').first[:id]}$/
> + end
> + end
> +
> + it 'should advertise the public and private addresses of the instance' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance[@state=RUNNING]').each do |r|
> + VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
> + get collection_url(:instances) + '/' + r[:id]
> + end
> + puts xml_response
> + (xml_response/'public_addresses').wont_be_empty
> + (xml_response/'public_addresses').size.must_equal 1
> + (xml_response/'public_addresses/address').each do |a|
> + a[:type].wont_be_nil
> + a.text.strip.wont_be_empty
> + end
> + (xml_response/'private_addresses').wont_be_empty
> + (xml_response/'private_addresses').size.must_equal 1
> + (xml_response/'private_addresses/address').each do |a|
> + a[:type].wont_be_nil
> + a.text.strip.wont_be_empty
> + end
> + end
> + end
> +
> + it 'should advertise the storage volumes used by the instance' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
> + get collection_url(:instances) + '/' + r[:id]
> + end
> + (xml_response/'storage_volumes').wont_be_empty
> + end
> + end
> +
> + it 'should advertise the list of actions that can be executed for each instance' do
> + auth_as_mock
> + get collection_url(:instances)
> + (xml_response/'instances/instance').each do |r|
> + VCR.use_cassette "#{__name__}_instance_#{r[:id]}" do
> + get collection_url(:instances) + '/' + r[:id]
> + end
> + (xml_response/'actions/link').wont_be_empty
> + (xml_response/'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 and destroy new instance using the image without realm' do
> + auth_as_mock
> + image_id = 'ami-e565ba8c'
> + VCR.use_cassette "#{__name__}_create_instance" do
> + post collection_url(:instances), { :image_id => image_id }
> + end
> + last_response.status.must_equal 201 # HTTP_CREATED
> + last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
> + instance_id = last_response.headers['Location'].split('/').last
> + # Get the instance and check if ID and image is set correctly
> + VCR.use_cassette "#{__name__}_get_instance" do
> + get collection_url(:instances) + '/' + instance_id
> + end
> + last_response.status.must_equal 200 # HTTP_OK
> + (xml_response/'instance').first[:id].must_equal instance_id
> + (xml_response/'instance/image').first[:id].must_equal image_id
> + 10.times do |i|
> + VCR.use_cassette "#{__name__}_pool_#{i}_instance" do
> + get collection_url(:instances) + '/' + instance_id
> + end
> + break if (xml_response/'instance/state').text == 'RUNNING'
> + sleep(10)
> + end
> + (xml_response/'instance/state').text.must_equal 'RUNNING'
> + # Delete created instance
> + VCR.use_cassette "#{__name__}_delete_instance" do
> + post collection_url(:instances) + '/' + instance_id + '/stop'
> + end
> + last_response.status.must_equal 202 # HTTP_NO_CONTENT
> + end
> +
> + it 'should allow to create and destroy new instance using the image within realm' do
> + auth_as_mock
> + image_id = 'ami-e565ba8c'
> + realm_id = 'us-east-1c'
> + VCR.use_cassette "#{__name__}_create_instance" do
> + post collection_url(:instances), { :image_id => image_id, :realm_id => realm_id }
> + end
> + last_response.status.must_equal 201 # HTTP_CREATED
> + last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
> + instance_id = last_response.headers['Location'].split('/').last
> + # Get the instance and check if ID and image is set correctly
> + VCR.use_cassette "#{__name__}_get_instance" do
> + get collection_url(:instances) + '/' + instance_id
> + end
> + last_response.status.must_equal 200 # HTTP_OK
> + (xml_response/'instance').first[:id].must_equal instance_id
> + (xml_response/'instance/image').first[:id].must_equal image_id
> + 10.times do |i|
> + VCR.use_cassette "#{__name__}_pool_#{i}_instance" do
> + get collection_url(:instances) + '/' + instance_id
> + end
> + break if (xml_response/'instance/state').text == 'RUNNING'
> + sleep(10)
> + end
> + (xml_response/'instance/state').text.must_equal 'RUNNING'
> + (xml_response/'instance/realm').first[:id].must_equal realm_id
> + # Delete created instance
> + VCR.use_cassette "#{__name__}_delete_instance" do
> + post collection_url(:instances) + '/' + instance_id + '/stop'
> + end
> + last_response.status.must_equal 202 # HTTP_NO_CONTENT
> + end
> +
> + it 'should allow to create and destroy new instance using the first available image and first hardware_profile' do
> + auth_as_mock
> + image_id = 'ami-e565ba8c'
> + hwp_id = 'm1.small'
> + VCR.use_cassette "#{__name__}_create_instance" do
> + post collection_url(:instances), { :image_id => image_id, :hwp_id => hwp_id }
> + end
> + last_response.status.must_equal 201 # HTTP_CREATED
> + last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
> + instance_id = last_response.headers['Location'].split('/').last
> + # Get the instance and check if ID and image is set correctly
> + VCR.use_cassette "#{__name__}_get_instance" do
> + get collection_url(:instances) + '/' + instance_id
> + end
> + last_response.status.must_equal 200 # HTTP_OK
> + (xml_response/'instance').first[:id].must_equal instance_id
> + (xml_response/'instance/image').first[:id].must_equal image_id
> + 10.times do |i|
> + VCR.use_cassette "#{__name__}_pool_#{i}_instance" do
> + get collection_url(:instances) + '/' + instance_id
> + end
> + break if (xml_response/'instance/state').text == 'RUNNING'
> + sleep(10)
> + end
> + (xml_response/'instance/state').text.must_equal 'RUNNING'
> + (xml_response/'instance/hardware_profile').first[:id].must_equal hwp_id
> + # Delete created instance
> + VCR.use_cassette "#{__name__}_delete_instance" do
> + post collection_url(:instances) + '/' + instance_id + '/stop'
> + end
> + last_response.status.must_equal 202 # HTTP_NO_CONTENT
> + end
> +
> +end
> diff --git a/server/tests/drivers/ec2/keys_test.rb b/server/tests/drivers/ec2/keys_test.rb
> new file mode 100644
> index 0000000..814de38
> --- /dev/null
> +++ b/server/tests/drivers/ec2/keys_test.rb
> @@ -0,0 +1,181 @@
> +$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
> +require 'tests/drivers/ec2/common'
> +
> +describe 'Deltacloud API Keys' do
> +
> + before do
> + Timecop.freeze(FREEZED_TIME)
> + VCR.insert_cassette __name__
> + end
> +
> + after do
> + VCR.eject_cassette
> + end
> +
> + include Deltacloud::Test
> +
> + it 'must advertise have the keys collection in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link[@rel=keys]').wont_be_empty
> + end
> +
> + it 'must require authentication to access the "key" collection' do
> + get collection_url(:keys)
> + last_response.status.must_equal 401
> + end
> +
> + it 'should respond with HTTP_OK when accessing the :keys collection with authentication' do
> + auth_as_mock
> + get collection_url(:keys)
> + last_response.status.must_equal 200
> + end
> +
> + it 'should support the JSON media type' do
> + auth_as_mock
> + header 'Accept', 'application/json'
> + get collection_url(:keys)
> + last_response.status.must_equal 200
> + last_response.headers['Content-Type'].must_equal 'application/json'
> + end
> +
> + it 'must include the ETag in HTTP headers' do
> + auth_as_mock
> + get collection_url(:keys)
> + last_response.headers['ETag'].wont_be_nil
> + end
> +
> + it 'must have the "keys" element on top level' do
> + auth_as_mock
> + get collection_url(:keys)
> + xml_response.root.name.must_equal 'keys'
> + end
> +
> + it 'must have some "key" elements inside "keys"' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').wont_be_empty
> + end
> +
> + it 'must tell the kind of "key" elements inside "keys"' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').each do |k|
> + k[:type].must_match /(key|password)/
> + end
> + end
> +
> + it 'must provide the :id attribute for each key in collection' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').each do |r|
> + r[:id].wont_be_nil
> + end
> + end
> +
> + it 'must include the :href attribute for each "key" element in collection' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').each do |r|
> + r[:href].wont_be_nil
> + end
> + end
> +
> + it 'must use the absolute URL in each :href attribute' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').each do |r|
> + r[:href].must_match /^http/
> + end
> + end
> +
> + it 'must have the URL ending with the :id of the key' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').each do |r|
> + r[:href].must_match /#{r[:id]}$/
> + end
> + end
> +
> + it 'must return the list of valid parameters for the :index action' do
> + auth_as_mock
> + options collection_url(:keys) + '/index'
> + last_response.headers['Allow'].wont_be_nil
> + end
> +
> + it 'must have the "name" element defined for each key in collection' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').each do |r|
> + (r/'name').wont_be_empty
> + end
> + end
> +
> +
> + it 'must return the full "key" when following the URL in key element' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').each do |r|
> + get collection_url(:keys) + '/' + r[:id]
> + last_response.status.must_equal 200
> + end
> + end
> +
> + it 'must have the "name" element for the key and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').each do |r|
> + VCR.use_cassette "#{__name__}_key_#{r[:id]}" do
> + get collection_url(:keys) + '/' + r[:id]
> + end
> + (xml_response/'name').wont_be_empty
> + (xml_response/'name').first.text.must_equal((r/'name').first.text)
> + end
> + end
> +
> + it 'must have the "name" element for the key and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').each do |r|
> + VCR.use_cassette "#{__name__}_key_#{r[:id]}" do
> + get collection_url(:keys) + '/' + r[:id]
> + end
> + (xml_response/'state').wont_be_empty
> + (xml_response/'state').first.text.must_equal((r/'state').first.text)
> + end
> + end
> +
> + it 'should advertise the list of actions that can be executed for each key' do
> + auth_as_mock
> + get collection_url(:keys)
> + (xml_response/'keys/key').each do |r|
> + VCR.use_cassette "#{__name__}_key_#{r[:id]}" do
> + get collection_url(:keys) + '/' + r[:id]
> + end
> + (xml_response/'actions/link').wont_be_empty
> + (xml_response/'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 a new key and then remove it' do
> + auth_as_mock
> + key_name = Time.now.to_i.to_s
> + post collection_url(:keys), {
> + :name => 'test_key_'+key_name
> + }
> + last_response.status.must_equal 201 # HTTP_CREATED
> + VCR.use_cassette "#{__name__}_key_#{key_name}" do
> + get collection_url(:keys) + '/' + 'test_key_'+key_name
> + end
> + last_response.status.must_equal 200 # HTTP_OK
> + VCR.use_cassette "#{__name__}_delete_key_#{key_name}" do
> + delete collection_url(:keys) + '/' + 'test_key_'+key_name
> + end
> + last_response.status.must_equal 204 # HTTP_NO_CONTENT
> + end
> +
> +end
> diff --git a/server/tests/drivers/ec2/realms_test.rb b/server/tests/drivers/ec2/realms_test.rb
> new file mode 100644
> index 0000000..8e8b325
> --- /dev/null
> +++ b/server/tests/drivers/ec2/realms_test.rb
> @@ -0,0 +1,146 @@
> +$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
> +require 'tests/drivers/ec2/common'
> +
> +describe 'Deltacloud API Realms' do
> + before do
> + Timecop.freeze(FREEZED_TIME)
> + VCR.insert_cassette __name__
> + end
> +
> + after do
> + VCR.eject_cassette
> + end
> +
> + include Deltacloud::Test
> +
> + it 'must advertise have the realms collection in API entrypoint' do
> + get Deltacloud[:root_url]
> + (xml_response/'api/link[@rel=realms]').wont_be_empty
> + end
> +
> + it 'must require authentication to access the "realm" collection' do
> + get collection_url(:realms)
> + last_response.status.must_equal 401
> + end
> +
> + it 'should respond with HTTP_OK when accessing the :realms collection with authentication' do
> + auth_as_mock
> + get collection_url(:realms)
> + last_response.status.must_equal 200
> + end
> +
> + it 'should support the JSON media type' do
> + auth_as_mock
> + header 'Accept', 'application/json'
> + get collection_url(:realms)
> + last_response.status.must_equal 200
> + last_response.headers['Content-Type'].must_equal 'application/json'
> + end
> +
> + it 'must include the ETag in HTTP headers' do
> + auth_as_mock
> + get collection_url(:realms)
> + last_response.headers['ETag'].wont_be_nil
> + end
> +
> + it 'must have the "realms" element on top level' do
> + auth_as_mock
> + get collection_url(:realms)
> + xml_response.root.name.must_equal 'realms'
> + end
> +
> + it 'must have some "realm" elements inside "realms"' do
> + auth_as_mock
> + get collection_url(:realms)
> + (xml_response/'realms/realm').wont_be_empty
> + end
> +
> + it 'must provide the :id attribute for each realm in collection' do
> + auth_as_mock
> + get collection_url(:realms)
> + (xml_response/'realms/realm').each do |r|
> + r[:id].wont_be_nil
> + end
> + end
> +
> + it 'must include the :href attribute for each "realm" element in collection' do
> + auth_as_mock
> + get collection_url(:realms)
> + (xml_response/'realms/realm').each do |r|
> + r[:href].wont_be_nil
> + end
> + end
> +
> + it 'must use the absolute URL in each :href attribute' do
> + auth_as_mock
> + get collection_url(:realms)
> + (xml_response/'realms/realm').each do |r|
> + r[:href].must_match /^http/
> + end
> + end
> +
> + it 'must have the URL ending with the :id of the realm' do
> + auth_as_mock
> + get collection_url(:realms)
> + (xml_response/'realms/realm').each do |r|
> + r[:href].must_match /#{r[:id]}$/
> + end
> + end
> +
> + it 'must return the list of valid parameters for the :index action' do
> + auth_as_mock
> + options collection_url(:realms) + '/index'
> + last_response.headers['Allow'].wont_be_nil
> + end
> +
> + it 'must have the "name" element defined for each realm in collection' do
> + auth_as_mock
> + get collection_url(:realms)
> + (xml_response/'realms/realm').each do |r|
> + (r/'name').wont_be_empty
> + end
> + end
> +
> + it 'must have the "state" element defined for each realm in collection' do
> + auth_as_mock
> + get collection_url(:realms)
> + (xml_response/'realms/realm').each do |r|
> + (r/'state').wont_be_empty
> + end
> + end
> + it 'must return the full "realm" when following the URL in realm element' do
> + auth_as_mock
> + get collection_url(:realms)
> + (xml_response/'realms/realm').each do |r|
> + VCR.use_cassette "#{__name__}_realm_id" do
> + get collection_url(:realms) + '/' + r[:id]
> + end
> + last_response.status.must_equal 200
> + end
> + end
> +
> + it 'must have the "name" element for the realm and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:realms)
> + (xml_response/'realms/realm').each do |r|
> + VCR.use_cassette "#{__name__}_realm_#{r[:id]}" do
> + get collection_url(:realms) + '/' + r[:id]
> + end
> + (xml_response/'name').wont_be_empty
> + (xml_response/'name').first.text.must_equal((r/'name').first.text)
> + end
> + end
> +
> + it 'must have the "state" element for the realm and it should match with the one in collection' do
> + auth_as_mock
> + get collection_url(:realms)
> + (xml_response/'realms/realm').each do |r|
> + VCR.use_cassette "#{__name__}_realm_r[:id]" do
> + get collection_url(:realms) + '/' + r[:id]
> + end
> + (xml_response/'state').wont_be_empty
> + (xml_response/'state').first.text.must_equal((r/'state').first.text)
> + end
> + end
> +
> +end
> --
> 1.7.10.2
>
--
Michal Fojtik
Sr. Software Engineer, Deltacloud API (http://deltacloud.org)