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/31 11:27:54 UTC

[PATCH core 1/3] 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


[PATCH core 2/3] EC2: Fixed the way how we handle describe_availability_zones to be 1.9 compatible

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/drivers/ec2/ec2_driver.rb |   11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index f7ef826..6454cce 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -159,10 +159,15 @@ module Deltacloud
 
         def realms(credentials, opts={})
           ec2 = new_client(credentials)
-          zone_id = opts ? opts[:id] : nil
           safely do
-            return ec2.describe_availability_zones(zone_id).collect do |realm|
-              convert_realm(realm)
+            if opts[:id] and !opts[:id].empty?
+              return ec2.describe_availability_zones([opts[:id]]).collect do |realm|
+                convert_realm(realm)
+              end
+            else
+              return ec2.describe_availability_zones.collect do |realm|
+                convert_realm(realm)
+              end
             end
           end
         end
-- 
1.7.10.2


Re: [PATCH core 1/3] Ec2: Added minitest suite for EC2 driver using VCR recording

Posted by "marios@redhat.com" <ma...@redhat.com>.
ok, found the problem... we are in different time zones :)

looking at your recordings they have something like: "+  recorded_at:
Thu, 24 May 2012 16:10:00 GMT" and then looking at where you freeze time
it says
FREEZED_TIME = Time.local(2012, 5, 24, 18, 10, 0).freeze .. i.e. 18:10
your time. Compensating for this I made FREEZED_TIME = Time.local(2012,
5, 24, 19, 10, 0).freeze (i.e. for my timezone):

# Running tests:

...............................................................................................................................................

Finished tests in -685740.867891s, -0.0002 tests/s, -0.0080 assertions/s.

143 tests, 5453 assertions, 0 failures, 0 errors, 0 skips



so now you just need to figure out how to make timecop play timezone
independently

marios



On 01/06/12 17:28, marios@redhat.com wrote:
> nack - still getting the same errors - patches apply fine but still
> making 'real' requests using the Timecop timestamp ...
> 
> 143 tests, 705 assertions, 28 failures, 7 errors, 0 skips
> rake aborted!
> Command failed with status (1): [/usr/bin/ruby -I"lib"
> -I"/usr/lib/ruby/gem...]
> 
> Tasks: TOP => test:ec2
> (See full trace by running task with --trace)
> 
> 
> 
> I'll send you a full trace by e-mail (2mb ... and can't attach files
> here)... sample trace looks like:
> 
> [marios@name server]$ rake test:ec2
> NOTE: Gem::Specification#has_rdoc= is deprecated with no replacement. It
> will be removed on or after 2011-10-01.
> Gem::Specification#has_rdoc= called from deltacloud-core.gemspec:67
> .
> /usr/bin/ruby -I"lib" -I"/usr/lib/ruby/gems/1.8/gems/rake-0.9.2.2/lib"
> "/usr/lib/ruby/gems/1.8/gems/rake-0.9.2.2/lib/rake/rake_test_loader.rb"
> "tests/drivers/ec2/hardware_profiles_test.rb"
> "tests/drivers/ec2/keys_test.rb" "tests/drivers/ec2/images_test.rb"
> "tests/drivers/ec2/api_test.rb" "tests/drivers/ec2/realms_test.rb"
> "tests/drivers/ec2/drivers_test.rb" "tests/drivers/ec2/instances_test.rb"
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/utils.rb:105:
> warning: already initialized constant HEX
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/utils.rb:107:
> warning: already initialized constant TO_REMEMBER
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/utils.rb:108:
> warning: already initialized constant ASCII
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/errors.rb:128:
> warning: already initialized constant DEFAULT_CLOSE_ON_4XX_PROBABILITY
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/parsers.rb:47:
> warning: already initialized constant DEFAULT_XML_LIBRARY
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/awsbase.rb:66:
> warning: already initialized constant AMAZON_PROBLEMS
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/awsbase.rb:86:
> warning: already initialized constant DEFAULT_SIGNATURE_VERSION
> Run options: --seed 2875
> 
> # Running tests:
> 
> ...............[NO HANDLED] Aws::AwsError: RequestExpired: Request has
> expired. Timestamp date is 2012-05-24T15:10:00.000Z
> REQUEST=ec2.us-east-1.amazonaws.com:443/?AWSAccessKeyId=AKIAI77KNAA7ZXRLL7GQ&Action=DescribeAvailabilityZones&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-05-24T15%3A10%3A00.000Z&Version=2010-08-31&Signature=5P9EvYlPFMbdHTeW2nW0%2B%2FaWogFuFGu4WM7tviLIqBk%3D
> 
> REQUEST ID=acc1911c-15af-4edf-8fac-8402fe5eed97
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/awsbase.rb:572:in
> `request_info_impl'
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ec2/ec2.rb:177:in `request_info'
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/awsbase.rb:586:in
> `request_cache_or_info'
> /usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ec2/ec2.rb:1133:in
> `describe_availability_zones'
> /home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/./helpers/../drivers/ec2/ec2_driver.rb:168:in
> `realms'
> /home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/./drivers/exceptions.rb:173:in
> `call'
> /home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/./drivers/exceptions.rb:173:in
> `safely'
> /home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/./helpers/../drivers/ec2/ec2_driver.rb:162:in
> `realms'
> /home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/./helpers/../drivers/ec2/ec2_driver.rb:760:in
> `valid_credentials?'
> /home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/server.rb:47:in
> `GET /api/?'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:1211:in `call'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:1211:in
> `compile!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in `[]'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in
> `route!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:801:in
> `route_eval'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in
> `route!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:822:in
> `process_route'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:820:in `catch'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:820:in
> `process_route'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:784:in
> `route!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:783:in `each'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:783:in
> `route!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:886:in
> `dispatch!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
> `invoke'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `catch'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
> `invoke'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:705:in `call'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:766:in
> `forward'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:835:in
> `route_missing'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:796:in
> `route!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:792:in
> `route!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:886:in
> `dispatch!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
> `invoke'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `catch'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
> `invoke'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:705:in `call'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:766:in
> `forward'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:835:in
> `route_missing'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:796:in
> `route!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:792:in
> `route!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:886:in
> `dispatch!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
> `invoke'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `catch'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
> `invoke'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
> /usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:705:in `call'
> /usr/lib/ruby/gems/1.8/gems/rack-protection-1.2.0/lib/rack/protection/xss_header.rb:22:in
> `call'
> /usr/lib/ruby/gems/1.8/gems/rack-protection-1.2.0/lib/rack/protection/path_traversal.rb:16:in
> `call'
> /usr/lib/ruby/gems/1.8/gems/rack-protection-1.2.0/lib/rack/protection/json_csrf.rb:17:in
> `call'
> 
> marios
> 
> On 31/05/12 12:27, mfojtik@redhat.com wrote:
>> 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
> 


Re: [PATCH core 1/3] Ec2: Added minitest suite for EC2 driver using VCR recording

Posted by "marios@redhat.com" <ma...@redhat.com>.
nack - still getting the same errors - patches apply fine but still
making 'real' requests using the Timecop timestamp ...

143 tests, 705 assertions, 28 failures, 7 errors, 0 skips
rake aborted!
Command failed with status (1): [/usr/bin/ruby -I"lib"
-I"/usr/lib/ruby/gem...]

Tasks: TOP => test:ec2
(See full trace by running task with --trace)



I'll send you a full trace by e-mail (2mb ... and can't attach files
here)... sample trace looks like:

[marios@name server]$ rake test:ec2
NOTE: Gem::Specification#has_rdoc= is deprecated with no replacement. It
will be removed on or after 2011-10-01.
Gem::Specification#has_rdoc= called from deltacloud-core.gemspec:67
.
/usr/bin/ruby -I"lib" -I"/usr/lib/ruby/gems/1.8/gems/rake-0.9.2.2/lib"
"/usr/lib/ruby/gems/1.8/gems/rake-0.9.2.2/lib/rake/rake_test_loader.rb"
"tests/drivers/ec2/hardware_profiles_test.rb"
"tests/drivers/ec2/keys_test.rb" "tests/drivers/ec2/images_test.rb"
"tests/drivers/ec2/api_test.rb" "tests/drivers/ec2/realms_test.rb"
"tests/drivers/ec2/drivers_test.rb" "tests/drivers/ec2/instances_test.rb"
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/utils.rb:105:
warning: already initialized constant HEX
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/utils.rb:107:
warning: already initialized constant TO_REMEMBER
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/utils.rb:108:
warning: already initialized constant ASCII
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/errors.rb:128:
warning: already initialized constant DEFAULT_CLOSE_ON_4XX_PROBABILITY
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/parsers.rb:47:
warning: already initialized constant DEFAULT_XML_LIBRARY
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/awsbase.rb:66:
warning: already initialized constant AMAZON_PROBLEMS
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/awsbase.rb:86:
warning: already initialized constant DEFAULT_SIGNATURE_VERSION
Run options: --seed 2875

# Running tests:

...............[NO HANDLED] Aws::AwsError: RequestExpired: Request has
expired. Timestamp date is 2012-05-24T15:10:00.000Z
REQUEST=ec2.us-east-1.amazonaws.com:443/?AWSAccessKeyId=AKIAI77KNAA7ZXRLL7GQ&Action=DescribeAvailabilityZones&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-05-24T15%3A10%3A00.000Z&Version=2010-08-31&Signature=5P9EvYlPFMbdHTeW2nW0%2B%2FaWogFuFGu4WM7tviLIqBk%3D

REQUEST ID=acc1911c-15af-4edf-8fac-8402fe5eed97
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/awsbase.rb:572:in
`request_info_impl'
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ec2/ec2.rb:177:in `request_info'
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ses/../awsbase/awsbase.rb:586:in
`request_cache_or_info'
/usr/lib/ruby/gems/1.8/gems/aws-2.5.6/lib/ec2/ec2.rb:1133:in
`describe_availability_zones'
/home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/./helpers/../drivers/ec2/ec2_driver.rb:168:in
`realms'
/home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/./drivers/exceptions.rb:173:in
`call'
/home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/./drivers/exceptions.rb:173:in
`safely'
/home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/./helpers/../drivers/ec2/ec2_driver.rb:162:in
`realms'
/home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/./helpers/../drivers/ec2/ec2_driver.rb:760:in
`valid_credentials?'
/home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/tests/drivers/ec2/../../../tests/drivers/ec2/../../../lib/deltacloud/server.rb:47:in
`GET /api/?'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:1211:in `call'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:1211:in
`compile!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in `[]'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in
`route!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:801:in
`route_eval'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in
`route!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:822:in
`process_route'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:820:in `catch'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:820:in
`process_route'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:784:in
`route!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:783:in `each'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:783:in
`route!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:886:in
`dispatch!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
`invoke'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `catch'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
`invoke'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:705:in `call'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:766:in
`forward'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:835:in
`route_missing'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:796:in
`route!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:792:in
`route!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:886:in
`dispatch!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
`invoke'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `catch'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
`invoke'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:705:in `call'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:766:in
`forward'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:835:in
`route_missing'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:796:in
`route!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:792:in
`route!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:886:in
`dispatch!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
`invoke'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `catch'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in
`invoke'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
/usr/lib/ruby/gems/1.8/gems/sinatra-1.3.2/lib/sinatra/base.rb:705:in `call'
/usr/lib/ruby/gems/1.8/gems/rack-protection-1.2.0/lib/rack/protection/xss_header.rb:22:in
`call'
/usr/lib/ruby/gems/1.8/gems/rack-protection-1.2.0/lib/rack/protection/path_traversal.rb:16:in
`call'
/usr/lib/ruby/gems/1.8/gems/rack-protection-1.2.0/lib/rack/protection/json_csrf.rb:17:in
`call'

marios

On 31/05/12 12:27, mfojtik@redhat.com wrote:
> 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