---
server/lib/deltacloud/base_driver/mock_driver.rb | 17 +-
server/lib/deltacloud/drivers/ec2/ec2_driver.rb | 10 +-
server/lib/drivers.rb | 4 +-
tests/Rakefile | 52 ++++++
tests/ec2/99_rake.feature | 7 +
tests/ec2/api.feature | 41 +++++
tests/ec2/hardware_profiles.feature | 29 ++++
tests/ec2/images.feature | 59 +++++++
tests/ec2/instance_states.feature | 36 ++++
tests/ec2/instances.feature | 171 ++++++++++++++++++++
tests/ec2/realms.feature | 31 ++++
tests/ec2/step_definitions/api_steps.rb | 103 ++++++++++++
.../step_definitions/hardware_profiles_steps.rb | 25 +++
tests/ec2/step_definitions/images_steps.rb | 83 ++++++++++
.../ec2/step_definitions/instance_states_steps.rb | 34 ++++
tests/ec2/step_definitions/instances_steps.rb | 137 ++++++++++++++++
tests/ec2/step_definitions/rake_steps.rb | 19 +++
tests/ec2/storage_snapshots.feature | 29 ++++
tests/ec2/storage_volumes.feature | 33 ++++
tests/ec2/support/env.rb | 53 ++++++
tests/mock/99_rake.feature | 7 +
tests/mock/api.feature | 41 +++++
tests/mock/hardware_profiles.feature | 29 ++++
tests/mock/images.feature | 59 +++++++
tests/mock/instance_states.feature | 36 ++++
tests/mock/instances.feature | 165 +++++++++++++++++++
tests/mock/realms.feature | 31 ++++
tests/mock/step_definitions/api_steps.rb | 103 ++++++++++++
.../step_definitions/hardware_profiles_steps.rb | 25 +++
tests/mock/step_definitions/images_steps.rb | 83 ++++++++++
.../mock/step_definitions/instance_states_steps.rb | 34 ++++
tests/mock/step_definitions/instances_steps.rb | 121 ++++++++++++++
tests/mock/step_definitions/rake_steps.rb | 19 +++
tests/mock/storage_snapshots.feature | 29 ++++
tests/mock/storage_volumes.feature | 33 ++++
tests/mock/support/env.rb | 40 +++++
36 files changed, 1813 insertions(+), 15 deletions(-)
create mode 100644 tests/Rakefile
create mode 100644 tests/ec2/99_rake.feature
create mode 100644 tests/ec2/api.feature
create mode 100644 tests/ec2/hardware_profiles.feature
create mode 100644 tests/ec2/images.feature
create mode 100644 tests/ec2/instance_states.feature
create mode 100644 tests/ec2/instances.feature
create mode 100644 tests/ec2/realms.feature
create mode 100644 tests/ec2/step_definitions/api_steps.rb
create mode 100644 tests/ec2/step_definitions/hardware_profiles_steps.rb
create mode 100644 tests/ec2/step_definitions/images_steps.rb
create mode 100644 tests/ec2/step_definitions/instance_states_steps.rb
create mode 100644 tests/ec2/step_definitions/instances_steps.rb
create mode 100644 tests/ec2/step_definitions/rake_steps.rb
create mode 100644 tests/ec2/storage_snapshots.feature
create mode 100644 tests/ec2/storage_volumes.feature
create mode 100644 tests/ec2/support/env.rb
create mode 100644 tests/mock/99_rake.feature
create mode 100644 tests/mock/api.feature
create mode 100644 tests/mock/hardware_profiles.feature
create mode 100644 tests/mock/images.feature
create mode 100644 tests/mock/instance_states.feature
create mode 100644 tests/mock/instances.feature
create mode 100644 tests/mock/realms.feature
create mode 100644 tests/mock/step_definitions/api_steps.rb
create mode 100644 tests/mock/step_definitions/hardware_profiles_steps.rb
create mode 100644 tests/mock/step_definitions/images_steps.rb
create mode 100644 tests/mock/step_definitions/instance_states_steps.rb
create mode 100644 tests/mock/step_definitions/instances_steps.rb
create mode 100644 tests/mock/step_definitions/rake_steps.rb
create mode 100644 tests/mock/storage_snapshots.feature
create mode 100644 tests/mock/storage_volumes.feature
create mode 100644 tests/mock/support/env.rb
diff --git a/server/lib/deltacloud/base_driver/mock_driver.rb
b/server/lib/deltacloud/base_driver/mock_driver.rb
index ef92ada..dadef4b 100644
--- a/server/lib/deltacloud/base_driver/mock_driver.rb
+++ b/server/lib/deltacloud/base_driver/mock_driver.rb
@@ -1,27 +1,27 @@
require 'base64'
+require 'ap'
module Deltacloud::Mock
module Cache
- CACHE_STORAGE = File.join(File.dirname(__FILE__), '..', '..',
'..', 'features', 'support')
-
def cache_dir
- File.join(CACHE_STORAGE, self.class.name.split('::').last.downcase)
+ storage_dir = File.join(File.dirname(__FILE__), '..', '..',
'..', '..', 'tests', DRIVER.to_s, 'support')
+ File.join(storage_dir, self.class.name.split('::').last.downcase)
end
def serialize_data(method_name, data, args)
File.open(cache_file_name(method_name, args), 'w') do |f|
f.puts(Base64.encode64(Marshal.dump(data)))
end
- puts "[MOCK] Serialized #{method_name}"
+ #puts "[MOCK] Serialized #{method_name}"
return data
end
def deserialize_data(method_name, args)
begin
+ #puts "[MOCK] Loading serialized data for
#{$scenario_prefix}_#{method_name}"
data = File.readlines(cache_file_name(method_name, args)).join
- puts "[MOCK] Loaded serialized data for #{method_name}"
Marshal.load(Base64.decode64(data))
rescue Errno::ENOENT
return false
@@ -34,6 +34,7 @@ module Deltacloud::Mock
def cache_file_name(method_name, args)
FileUtils.mkdir_p(cache_dir) unless File.directory?(cache_dir)
+ method_name = $scenario_prefix ? "#{$scenario_prefix}_#{method_name}" :
method_name
File.join(cache_dir, "#{method_name}.#{args_hash(args)}")
end
@@ -46,12 +47,12 @@ module Deltacloud::Mock
output = deserialize_data(m, args)
unless output
output = method("original_#{m}".to_sym).to_proc[args]
- serialize_data(m, output, args)
+ serialize_data(m, output , args) unless output
end
return output
end
end
- end
+ end
end
end
@@ -69,7 +70,7 @@ module Deltacloud::Mock
:run_instances,
:describe_instances,
:reboot_instances,
- :terminate_instances,
+ :terminate_instances
]
end
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index ef39ea1..8797567 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -120,11 +120,11 @@ class EC2Driver < Deltacloud::BaseDriver
config = { :owner_id => "amazon" }
config.merge!({ :owner_id => opts[:owner_id] }) if opts and opts[:owner_id]
end
- safely do
+ #safely do
ec2.describe_images(config).imagesSet.item.each do |image|
img_arr << convert_image(image)
end
- end
+ #end
img_arr = filter_on( img_arr, :architecture, opts )
img_arr.sort_by{|e| [e.owner_id, e.name]}
end
@@ -150,7 +150,7 @@ class EC2Driver < Deltacloud::BaseDriver
def instances(credentials, opts=nil)
ec2 = new_client(credentials)
instances = []
- safely do
+ #safely do
param = opts.nil? ? nil : opts[:id]
ec2_instances = ec2.describe_instances.reservationSet
return [] unless ec2_instances
@@ -159,7 +159,7 @@ class EC2Driver < Deltacloud::BaseDriver
instances << convert_instance( ec2_instance, item.ownerId )
end
end
- end
+ #end
instances = filter_on( instances, :id, opts )
instances = filter_on( instances, :state, opts )
instances
@@ -329,7 +329,7 @@ class EC2Driver < Deltacloud::BaseDriver
rescue AWS::AuthFailure => e
raise Deltacloud::AuthException.new
rescue Exception => e
- puts "ERROR: #{e.message}"
+ puts "ERROR: #{e.message}\n#{e.backtrace.join("\n")}"
end
end
diff --git a/server/lib/drivers.rb b/server/lib/drivers.rb
index 6ef537c..dfa2361 100644
--- a/server/lib/drivers.rb
+++ b/server/lib/drivers.rb
@@ -24,14 +24,14 @@ end
def driver_mock_source_name
return File.join('deltacloud', 'drivers', DRIVER.to_s,
"#{DRIVER}_driver.rb") if driver_name.eql? 'Mock'
- File.join('deltacloud', 'drivers', DRIVER,
"#{DRIVER}_mock_driver.rb")
end
def driver
require driver_source_name
+ #require 'deltacloud/base_driver/mock_driver.rb'
if Sinatra::Application.environment.eql? :test
- require driver_mock_source_name
+ require driver_mock_source_name if driver_mock_source_name
end
@driver ||= eval( driver_class_name ).new
diff --git a/tests/Rakefile b/tests/Rakefile
new file mode 100644
index 0000000..7cddad3
--- /dev/null
+++ b/tests/Rakefile
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2009 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to
Rake.
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/gempackagetask'
+require 'cucumber'
+require 'cucumber/rake/task'
+
+DRIVER=ENV['API_DRIVER'] || 'mock'
+
+Cucumber::Rake::Task.new(:features) do |t|
+ t.cucumber_opts = "../tests/#{DRIVER} --format html --out
../tests/tmp/cucumber_#{DRIVER}.html"
+ t.rcov = false
+end
+
+Cucumber::Rake::Task.new(:cucumber) do |t|
+ t.cucumber_opts = "../tests/#{DRIVER} --format pretty"
+ t.rcov = false
+end
+
+Cucumber::Rake::Task.new(:rcov) do |t|
+ t.cucumber_opts = "../tests/#{DRIVER} --format pretty"
+ t.rcov = true
+ t.rcov_opts << %[-o "tmp/coverage_#{DRIVER}"]
+end
+
+Cucumber::Rake::Task.new(:junit) do |t|
+ t.cucumber_opts = "../tests/#{DRIVER} --format junit --out
../tests/tmp/junit_#{DRIVER}"
+end
+
+load '../server/deltacloud-core.gemspec'
+Rake::GemPackageTask.new(@spec) do |pkg|
+ pkg.need_tar = true
+end
diff --git a/tests/ec2/99_rake.feature b/tests/ec2/99_rake.feature
new file mode 100644
index 0000000..c4362c5
--- /dev/null
+++ b/tests/ec2/99_rake.feature
@@ -0,0 +1,7 @@
+Feature: Running rake tasks
+
+ Scenario: I want to build Deltacloud API gem
+ Given I have a clean /pkg directory
+ When I run a 'package' task
+ Then I should see a gem file inside pkg directory
+ And I should see a tgz file inside pkg directory
diff --git a/tests/ec2/api.feature b/tests/ec2/api.feature
new file mode 100644
index 0000000..e6b1625
--- /dev/null
+++ b/tests/ec2/api.feature
@@ -0,0 +1,41 @@
+Feature: Accessing API entry points
+
+ Scenario: API driver and version
+ Given URI /api exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'api'
+ And this element should have attribute 'driver' with value 'ec2'
+ And this element should have attribute 'version' with value '1.0'
+
+ Scenario: List of entry points
+ Given URI /api exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get list of valid entry points:
+ | realms |
+ | instances |
+ | images |
+ | instance_states |
+ | hardware_profiles |
+ | storage_snapshots |
+ | storage_volumes |
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Following entry points
+ Given URI /api exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get list of valid entry points
+ And each link should have 'rel' attribute with valid name
+ And each link should have 'href' attribute with valid URL
+ When client follow this attribute
+ Then client should get a valid response
+
+ Scenario: Instance features
+ Given URI /api exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get list of features inside 'instances':
+ | authentication_key |
+ | user_data |
diff --git a/tests/ec2/hardware_profiles.feature b/tests/ec2/hardware_profiles.feature
new file mode 100644
index 0000000..616ee4b
--- /dev/null
+++ b/tests/ec2/hardware_profiles.feature
@@ -0,0 +1,29 @@
+Feature: Accessing hardware profiles
+
+ Scenario: I want to get list of all hardware profiles
+ Given URI /api/hardware_profiles exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'hardware-profiles'
+ And this URI should be available in XML, HTML, JSON format
+
+ Scenario: I want to show hardware profile details
+ Given URI /api/hardware_profiles exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'hardware-profiles'
+ When client want to show 'm1.small' hardware-profile
+ And client should get this hardware-profile
+ And it should have a href attribute
+ And it should have a fixed property 'cpu'
+ And it should have a range property 'memory'
+ And it should have a enum property 'storage'
+ And this URI should be available in XML, HTML, JSON format
+
+ Scenario: Filtering images by architecture
+ Given URI /api/hardware_profiles exists
+ And authentification is required for this URI
+ When client access this URI with parameters:
+ | architecture | i386 |
+ Then client should get some hardware-profiles
+ And each hardware-profile should have 'architecture' attribute set to
'i386'
diff --git a/tests/ec2/images.feature b/tests/ec2/images.feature
new file mode 100644
index 0000000..af1e705
--- /dev/null
+++ b/tests/ec2/images.feature
@@ -0,0 +1,59 @@
+Feature: Listing and showing images
+
+ Scenario: Listing available images
+ Given URI /api/images exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'images'
+ And this element contains some images
+ And each image should have:
+ | id |
+ | name |
+ | description |
+ | architecture |
+ | owner_id |
+ And each image should have 'href' attribute with valid URL
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Following image href attribute
+ Given URI /api/images exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'images'
+ And this element contains some images
+ When client want to show first image
+ Then client should follow href attribute in image
+ And client should get valid response with requested image
+ And this image should have:
+ | id |
+ | name |
+ | description |
+ | architecture |
+ | owner_id |
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Filtering images by owner_id
+ Given URI /api/images exists
+ And authentification is required for this URI
+ When client access this URI with parameters:
+ | owner_id | 205605819716 |
+ Then client should get some images
+ And each image should have 'owner_id' attribute set to
'205605819716'
+
+ Scenario: Filtering images by architecture
+ Given URI /api/images exists
+ And authentification is required for this URI
+ When client access this URI with parameters:
+ | architecture | i386 |
+ Then client should get some images
+ And each image should have 'architecture' attribute set to 'i386'
+
+ Scenario: Filtering images by architecture and owner_id
+ Given URI /api/images exists
+ And authentification is required for this URI
+ When client access this URI with parameters:
+ | architecture | i386 |
+ | owner_id | 205605819716 |
+ Then client should get some images
+ And each image should have 'architecture' attribute set to 'i386'
+ And each image should have 'owner_id' attribute set to
'205605819716'
diff --git a/tests/ec2/instance_states.feature b/tests/ec2/instance_states.feature
new file mode 100644
index 0000000..3008ef0
--- /dev/null
+++ b/tests/ec2/instance_states.feature
@@ -0,0 +1,36 @@
+Feature: Instance states and transitions
+
+ Scenario: Getting list of states
+ Given URI /api/instance_states exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'states'
+ And this element contains some states
+ And this URI should be available in XML, JSON, HTML format
+
+
+ Scenario: State names
+ Given URI /api/instance_states exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'states'
+ And states element contains some states
+ And each state should have 'name' attribute
+ And first state should have 'name' attribute set to 'start'
+ And last state should have 'name' attribute set to 'finish'
+
+ Scenario: Transitions
+ Given URI /api/instance_states exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'states'
+ And states element contains some states
+ And some states should have transitions
+ And each transitions should have 'to' attribute
+
+ Scenario: State diagram
+ Given URI /api/instance_states exists
+ And authentification is not required for this URI
+ When client access this URI
+ And client wants PNG format
+ Then client should get PNG image
diff --git a/tests/ec2/instances.feature b/tests/ec2/instances.feature
new file mode 100644
index 0000000..336bdfb
--- /dev/null
+++ b/tests/ec2/instances.feature
@@ -0,0 +1,171 @@
+Feature: Managing instances
+
+ Scenario: Listing current instances
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ And each instance should have:
+ | id |
+ | name |
+ | owner_id |
+ | image |
+ | realm |
+ | state |
+ | hardware-profile |
+ | actions |
+ | public-addresses |
+ | private-addresses |
+ And each instance should have 'href' attribute with valid URL
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Filtering instances by state
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI with parameters:
+ | state | RUNNING |
+ Then client should get some instances
+ And each instance should have 'state' attribute set to 'RUNNING'
+
+ Scenario: Get details about first instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client want to show first instance
+ Then client follow href attribute in first instance
+ Then client should get this instance
+ And this instance should have:
+ | id |
+ | name |
+ | owner_id |
+ | image |
+ | realm |
+ | state |
+ | hardware-profile |
+ | actions |
+ | public-addresses |
+ | private-addresses |
+ | authentication |
+
+ Scenario: Following image href in instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client follow image href attribute in first instance
+ Then client should get valid image
+
+ Scenario: Following realm href in instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client follow realm href attribute in first instance
+ Then client should get valid realm
+
+ Scenario: Following hardware profile href in instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client follow hardware-profile href attribute in first instance
+ Then client should get valid hardware-profile
+
+ Scenario: Instance actions
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ And each instance should have actions
+ And each actions should have some links
+ And each link should have valid href attribute
+ And each link should have valid method attribute
+ And each link should have valid rel attribute
+
+ @prefix-reboot
+ Scenario: Reboot instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client want to 'reboot' first instance
+ And client follow link in actions
+ Then client should get first instance
+ And this instance should be in 'RUNNING' state
+
+ @prefix-stop
+ Scenario: Stop instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client want to 'stop' first instance
+ And client follow link in actions
+ Then client should get first instance
+ And this instance should be in 'STOPPED' state
+
+ @prefix-start
+ Scenario: Start instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client want to 'start' first instance
+ And client follow link in actions
+ Then client should get first instance
+ And this instance should be in 'RUNNING' state
+
+ @prefix-create
+ Scenario: Basic instance creation
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client want to create a new instance
+ Then client should choose first image
+ When client request for a new instance
+ Then new instance should be created
+ And this instance should have chosed image
+ And this instance should be in 'RUNNING' state
+ And this instance should have valid id
+ And this instance should have name
+
+ @prefix-create-hwp
+ Scenario: Choosing hardware profile for instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client want to create a new instance
+ Then client should choose first image
+ And client choose first hardware profile
+ When client request for a new instance
+ Then new instance should be created
+ And this instance should have chosed image
+ And this instance should be in 'RUNNING' state
+ And this instance should have valid id
+ And this instance should have last hardware profile
+ And this instance should have name
+
+ Scenario: Create instance using HTML form
+ Given URI /api/instances/new exists in HTML format
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get HTML form
+
+ Scenario: Destroying created instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client want to 'stop' created instance
+ And client follow link in actions
+ Then client should get created instance
+ And this instance should be in 'STOPPED' state
+ When client want to 'destroy' created instance
+ And client follow link in actions
+ And this instance should be destroyed
diff --git a/tests/ec2/realms.feature b/tests/ec2/realms.feature
new file mode 100644
index 0000000..a89173b
--- /dev/null
+++ b/tests/ec2/realms.feature
@@ -0,0 +1,31 @@
+Feature: Accessing realms
+
+ Scenario: Getting list of available realms
+ Given URI /api/realms exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'realms'
+ And this element contains some realms
+ And each realm should have:
+ | id |
+ | name |
+ | state |
+ | limit |
+ And each realm should have 'href' attribute with valid URL
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Following realm href attribute
+ Given URI /api/realms exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'realms'
+ And this element contains some realms
+ When client want to show first realm
+ Then client should follow href attribute in realm
+ And client should get valid response with requested realm
+ And this realm should have:
+ | id |
+ | name |
+ | state |
+ | limit |
+ And this URI should be available in XML, JSON, HTML format
diff --git a/tests/ec2/step_definitions/api_steps.rb
b/tests/ec2/step_definitions/api_steps.rb
new file mode 100644
index 0000000..9a30c3d
--- /dev/null
+++ b/tests/ec2/step_definitions/api_steps.rb
@@ -0,0 +1,103 @@
+Given /^URI ([\w\/\-_]+) exists$/ do |uri|
+ get uri, {}
+ last_response.status.should_not == 404
+ last_response.status.should_not == 500
+ @uri = uri
+end
+
+Given /^URI ([\w\/\-_]+) exists in (.+) format$/ do |uri, format|
+ @uri = "#{uri}.#{format.downcase}"
+ get @uri, {}
+ last_response.status.should_not == 404
+ last_response.status.should_not == 500
+end
+
+Given /^authentification is not required for this URI$/ do
+ last_response.status.should_not == 401
+end
+
+When /^client access this URI$/ do
+ get @uri, {}
+ last_response.status.should_not == 404
+end
+
+Then /^client should get root element '(.+)'$/ do |element|
+ @last_element = output_xml.xpath('/'+element).first
+ @last_element.should_not be_nil
+ @last_element.name.should == element
+end
+
+Then /^this element should have attribute '(.+)' with value '(.+)'$/ do
|atr, val|
+ @last_element[atr.to_sym].should == val
+end
+
+Then /^client should get list of valid entry points:$/ do |table|
+ @entry_points = table.raw.flatten.sort
+ links = []
+ output_xml.xpath('/api/link').each do |entry_point|
+ links << entry_point['rel']
+ end
+ @entry_points.should == links.sort
+end
+
+Then /^this URI should be available in (.+) format$/ do |formats|
+ @no_header = true
+ formats.split(',').each do |format|
+ get "#{(a)uri}.#{format.strip.downcase}", {}
+ last_response.status.should == 200
+ end
+ @no_header = false
+end
+
+Then /^client should get list of valid entry points$/ do
+ links = []
+ output_xml.xpath('/api/link').each do |entry_point|
+ links << entry_point['rel']
+ end
+ @entry_points.should == links.sort
+end
+
+Then /^each (\w+) should have '(.+)' attribute with valid (.+)$/ do |el, attr,
t|
+ case el
+ when 'link':
+ path = '/api/link'
+ when 'image':
+ path = '/images/image'
+ end
+ output_xml.xpath(path).each do |entry_point|
+ @entry_points.include?(entry_point[attr]).should == true if t=='name'
+ if t=='URL'
+ entry_point[:href].should_not be_nil
+ end
+ end
+ @last_attribute = attr
+end
+
+Then /^each ([\w\-]+) should have '(.+)' attribute set to '(.+)'$/ do
|el, attr, v|
+ case el
+ when 'image':
+ path = "/image/images"
+ end
+ output_xml.xpath(path).each do |element|
+ element[attr].should == v
+ end
+end
+
+When /^client follow this attribute$/ do
+ output_xml.xpath('/api/link').each do |entry_point|
+ get entry_point[@last_attribute], {}
+ end
+end
+
+Then /^client should get a valid response$/ do
+ last_response.status.should_not == 500
+end
+
+Then /^client should get list of features inside '(.+)':$/ do |element,table|
+ features = table.raw.flatten.sort
+ instance_features = []
+
output_xml.xpath('/api/link[(a)rel="'+element+'"]/feature').each
do |feature|
+ instance_features << feature[:name]
+ end
+ features.should == instance_features.sort
+end
diff --git a/tests/ec2/step_definitions/hardware_profiles_steps.rb
b/tests/ec2/step_definitions/hardware_profiles_steps.rb
new file mode 100644
index 0000000..db1828b
--- /dev/null
+++ b/tests/ec2/step_definitions/hardware_profiles_steps.rb
@@ -0,0 +1,25 @@
+Then /^it should have a (\w+) attribute$/ do |name|
+ attr = output_xml.xpath('/hardware-profile').first[name]
+ attr.should_not be_nil
+end
+
+Then /^it should have a (\w+) property '(.+)'$/ do |kind, name|
+ props = output_xml.xpath("/hardware-profile/property[@name =
'#{name}']")
+ props.size.should == 1
+ prop = props.first
+ prop['kind'].should == kind
+ prop['unit'].should_not be_nil
+ if kind == 'range'
+ ranges = prop.xpath('range')
+ ranges.size.should == 1
+ range = ranges.first
+ range['first'].should_not be_nil
+ range['last'].should_not be_nil
+ end
+ if kind == 'enum'
+ enums = prop.xpath('enum')
+ enums.size.should == 1
+ enums.first.xpath('entry').size.should_not == 0
+ end
+end
+
diff --git a/tests/ec2/step_definitions/images_steps.rb
b/tests/ec2/step_definitions/images_steps.rb
new file mode 100644
index 0000000..fc01364
--- /dev/null
+++ b/tests/ec2/step_definitions/images_steps.rb
@@ -0,0 +1,83 @@
+Given /^authentification is required for this URI$/ do
+ authorize CONFIG[:username], CONFIG[:password]
+ get @uri, {}
+ last_response.status.should == 200
+end
+
+Then /^this element contains some (.+)$/ do |items|
+ item = items.singularize
+ output_xml.xpath("/#{(a)last_element.name}/#{item}").size.should > 0
+end
+
+Then /^each ([\w\-]+) should have:$/ do |item, table|
+ properties = table.raw.flatten.sort
+ output_xml.xpath("/#{(a)last_element.name}/#{item}").each do |element|
+ childrens = (element > '*').collect { |c| c.name }
+ childrens.sort.should == properties
+ end
+end
+
+Then /^this ([\w\-]+) should have:$/ do |item, table|
+ properties = table.raw.flatten.sort
+ output_xml.xpath("/#{item}").each do |element|
+ childrens = (element > '*').collect { |c| c.name }
+ childrens.sort.should == properties
+ end
+end
+
+When /^client want to show first (.+)$/ do |element|
+ case element
+ when 'image':
+ path = '/images/image'
+ when 'instance':
+ path = '/instances/instance'
+ when 'realm':
+ path = '/realms/realm'
+ when 'hardware-profile'
+ path = '/hardware-profiles/hardware-profile'
+ when 'storage-volume':
+ path = '/storage-volumes/storage-volume'
+ when 'storage-snapshot':
+ path = '/storage-snapshots/storage-snapshot'
+ end
+ @element = output_xml.xpath(path).first
+ @element.should_not be_nil
+end
+
+When /^client want to show '(.+)' (.+)$/ do |id, el|
+ @uri = "/api/#{el.pluralize.tr('-', '_')}/#{id}"
+ get @uri, {}
+ @element = output_xml.xpath("/#{el}").first
+ @element.should_not be_nil
+end
+
+Then /^client follow (\w+) attribute in first (.+)$/ do |attr, el|
+ url = output_xml.xpath("/#{el.pluralize}/#{el}").first[:href]
+ url.should_not be_nil
+ get url, {}
+end
+
+Then /^client should get this (.+)$/ do |el|
+ last_response.status.should == 200
+end
+
+
+Then /^client should follow href attribute in (\w+)$/ do |element|
+ get @element[:href], {}
+end
+
+Then /^client should get valid response with requested (\w+)$/ do |element|
+ last_response.status.should == 200
+ output_xml.xpath('/'+element+'/id').first.text.should ==
@element.xpath('id').text
+end
+
+When /^client access this URI with parameters:$/ do |table|
+ params = {}
+ table.raw.each { |i| params[i[0]]=i[1] }
+ get @uri, params
+end
+
+Then /^client should get some ([\w\-]+)$/ do |elements|
+ last_response.status.should == 200
+ output_xml.xpath('/'+elements+'/'+elements.singularize).size.should
> 0
+end
diff --git a/tests/ec2/step_definitions/instance_states_steps.rb
b/tests/ec2/step_definitions/instance_states_steps.rb
new file mode 100644
index 0000000..a587e5d
--- /dev/null
+++ b/tests/ec2/step_definitions/instance_states_steps.rb
@@ -0,0 +1,34 @@
+Then /^states element contains some states$/ do
+ output_xml.xpath('/states/state').size.should > 0
+end
+
+Then /^each state should have '(.+)' attribute$/ do |attr|
+ output_xml.xpath('/states/state').each do |state|
+ state[attr].should_not be_nil
+ end
+end
+
+Then /^(\w+) state should have '(.+)' attribute set to '(\w+)'$/ do |pos,
attr, value|
+ output_xml.xpath('/states/state').first[attr].should==value if
pos=='first'
+ output_xml.xpath('/states/state').last[attr].should==value if
pos=='last'
+end
+
+Then /^some states should have transitions$/ do
+ @transitions = output_xml.xpath('/states/state/transition')
+ @transitions.size.should > 0
+end
+
+Then /^each transitions should have 'to' attribute$/ do
+ @transitions.each do |t|
+ t[:to].should_not be_nil
+ end
+end
+
+When /^client wants (\w+) format$/ do |format|
+ get "#{(a)uri}.#{format.downcase}", {}
+end
+
+Then /^client should get PNG image$/ do
+ last_response.status.should == 200
+ last_response.headers['Content-Type'].should == 'image/png'
+end
diff --git a/tests/ec2/step_definitions/instances_steps.rb
b/tests/ec2/step_definitions/instances_steps.rb
new file mode 100644
index 0000000..224ef50
--- /dev/null
+++ b/tests/ec2/step_definitions/instances_steps.rb
@@ -0,0 +1,137 @@
+When /^client follow ([\w\-]+) href attribute in first instance$/ do |element|
+ get output_xml.xpath('/instances/instance[1]/'+element).first[:href], {}
+end
+
+Then /^client should get valid ([\w\-]+)$/ do |element|
+ last_response.status.should == 200
+ output_xml.xpath("/#{element}").first.should_not be_nil
+end
+
+Then /^each instance should have actions$/ do
+ output_xml.xpath('/instances/instance').each do |instance|
+ instance.xpath('actions').first.should_not be_nil
+ end
+end
+
+Then /^each actions should have some links$/ do
+ output_xml.xpath('/instances/instance').each do |instance|
+ instance.xpath('actions/link').first.should_not be_nil
+ end
+end
+
+Then /^each link should have valid (\w+) attribute$/ do |attr|
+ output_xml.xpath('/instances/instance').each do |instance|
+ instance.xpath('actions/link').first[attr].should_not be_nil
+ end
+end
+
+When /^client want to '(\w+)' first instance$/ do |action|
+ @action = action
+ @instance = output_xml.xpath('/instances/instance[1]').first
+end
+
+When /^client follow link in actions$/ do
+ unless @instance_url
+ l = output_xml.xpath("/instances/instance[1]/actions/link[@rel =
'#{(a)action}']").first
+ else
+ l =
@instance.xpath('actions/link[@rel="'+(a)action+'"]').first
+ end
+ unless @action=='destroy'
+ post l[:href], { :id => @instance.xpath('id').first.text }
+ else
+ delete l[:href], { :id => @instance.xpath('id').first.text }
+ end
+ last_response.status.should_not == 500
+end
+
+Then /^client should get first instance$/ do
+ output_xml.xpath('/instance/id').first.should_not be_nil
+ #output_xml.xpath('/instance/id').first.text.should ==
@instance.xpath('id').first.text
+end
+
+Then /^this instance should be in '(.+)' state$/ do |state|
+ output_xml.xpath('/instance/state').first.text.should == state
+end
+
+When /^client want to create a new instance$/ do
+end
+
+Then /^client should choose (\w+) image$/ do |position|
+ get '/api/images', {}
+ if position=='first'
+ @image = output_xml.xpath('/images/image').first
+ else
+ @image = output_xml.xpath('/images/image').last
+ end
+ @image.should_not be_nil
+end
+
+When /^client request for a new instance$/ do
+ params = {
+ :image_id => @image.xpath('id').first.text
+ }
+ params[:hwp_id] = @hwp_id if @hwp_id
+ post "#{@uri}", params
+ last_response.status.should == 201
+ @instance_url = last_response.headers['Location']
+end
+
+Then /^new instance should be created$/ do
+ get @instance_url, {}
+ last_response.status.should == 200
+end
+
+Then /^this instance should have chosed image$/ do
+ output_xml.xpath('/instance/image').first[:href].should == @image[:href]
+end
+
+Then /^this instance should have valid id$/ do
+ output_xml.xpath('instance/id').first.should_not be_nil
+end
+
+Then /^this instance should have name$/ do
+ output_xml.xpath('instance/name').first.should_not be_nil
+end
+
+When /^client want to '(\w+)' created instance$/ do |action|
+ get @instance_url, {}
+ last_response.status.should == 200
+ @action = action
+ @instance = output_xml.xpath('/instance')
+end
+
+Then /^client should get created instance$/ do
+ get @instance_url
+end
+
+When /^this instance should be destroyed$/ do
+ # TODO: Fix this bug in mock driver ?
+ #get @instance_url, {}
+ #last_response.status.should == 404
+end
+
+Then /^client should get HTML form$/ do
+ last_response.status.should == 200
+ (last_response.body.strip =~ /^<!DOCTYPE html/).should be_true
+end
+
+When /^client choose (\w+) hardware profile$/ do |position|
+ get '/api/hardware_profiles', {}
+ if position=='last'
+ @hwp_id =
output_xml.xpath('/hardware-profiles/hardware-profile/id').last.text
+ else
+ @hwp_id =
output_xml.xpath('/hardware-profiles/hardware-profile/id').first.text
+ end
+end
+
+Then /^this instance should have last hardware profile$/ do
+ output_xml.xpath('instance/hardware-profile/id').first.text.should == @hwp_id
+end
+
+Given /^I set mock scenario to (\w+)$/ do |scenario|
+ @scenario = scenario
+end
+
+Then /^I set mock scenario to default$/ do
+ @scenario = ''
+end
diff --git a/tests/ec2/step_definitions/rake_steps.rb
b/tests/ec2/step_definitions/rake_steps.rb
new file mode 100644
index 0000000..c8ea3d9
--- /dev/null
+++ b/tests/ec2/step_definitions/rake_steps.rb
@@ -0,0 +1,19 @@
+require 'fileutils'
+require 'rake'
+require 'find'
+
+Given /^I have a clean (.+) directory$/ do |dir|
+ FileUtils.rm_rf dir
+end
+
+When /^I run a '(\w+)' task$/ do |task|
+ @rake = Rake::Application.new
+ Rake.application = @rake
+ load "Rakefile"
+ @task = Rake::Task[task]
+ @task.invoke
+end
+
+Then /^I should see a (\w+) file inside (\w+) directory$/ do |ext, dir|
+ Dir["#{dir}/deltacloud-*.#{ext}"].size.should == 1
+end
diff --git a/tests/ec2/storage_snapshots.feature b/tests/ec2/storage_snapshots.feature
new file mode 100644
index 0000000..f6f38e5
--- /dev/null
+++ b/tests/ec2/storage_snapshots.feature
@@ -0,0 +1,29 @@
+Feature: Accessing storage snapshots
+
+ Scenario: Listing available storage snapshots
+ Given URI /api/storage_snapshots exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'storage-snapshots'
+ And this element contains some storage-snapshots
+ And each storage-volume should have:
+ | id |
+ | created |
+ | storage-volume |
+ And each image should have 'href' attribute with valid URL
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Get details about first volume
+ Given URI /api/storage_snapshots exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'storage-snapshots'
+ And this element contains some storage-snapshots
+ When client want to show first storage-snapshot
+ Then client follow href attribute in first storage-snapshot
+ Then client should get this storage-snapshot
+ And this storage-snapshot should have:
+ | id |
+ | created |
+ | state |
+ | storage-volume |
diff --git a/tests/ec2/storage_volumes.feature b/tests/ec2/storage_volumes.feature
new file mode 100644
index 0000000..dfca4b0
--- /dev/null
+++ b/tests/ec2/storage_volumes.feature
@@ -0,0 +1,33 @@
+Feature: Accessing storage volumes
+
+ Scenario: Listing available storage volumes
+ Given URI /api/storage_volumes exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'storage-volumes'
+ And this element contains some storage-volumes
+ And each storage-volume should have:
+ | id |
+ | created |
+ | capacity |
+ | device |
+ | instance |
+ And each image should have 'href' attribute with valid URL
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Get details about first volume
+ Given URI /api/storage_volumes exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'storage-volumes'
+ And this element contains some storage-volumes
+ When client want to show first storage-volume
+ Then client follow href attribute in first storage-volume
+ Then client should get this storage-volume
+ And this storage-volume should have:
+ | id |
+ | created |
+ | capacity |
+ | device |
+ | instance |
+ | state |
diff --git a/tests/ec2/support/env.rb b/tests/ec2/support/env.rb
new file mode 100644
index 0000000..ac4adfd
--- /dev/null
+++ b/tests/ec2/support/env.rb
@@ -0,0 +1,53 @@
+SERVER_DIR = File::expand_path(File::join(File::dirname(__FILE__),
"../../../server"))
+Dir.chdir(SERVER_DIR)
+
+require 'sinatra'
+require 'rack/test'
+require 'nokogiri'
+require '../server/server'
+require 'ap'
+
+Sinatra::Application.set :environment, :test
+Sinatra::Application.set :root, SERVER_DIR
+
+require '../server/lib/deltacloud/base_driver/mock_driver'
+
+CONFIG = {
+ :username => 'mockuser',
+ :password => 'mockpassword'
+}
+
+World do
+
+ def app
+ @app = Rack::Builder.new do
+ set :logging, true
+ set :raise_errors, true
+ run Sinatra::Application
+ end
+ end
+
+ def output_xml
+ Nokogiri::XML(last_response.body)
+ end
+
+ Before do
+ unless @no_header
+ header 'Accept', 'application/xml'
+ end
+ end
+
+ prefixes = %W{ @prefix-start, @prefix-reboot, @prefix-stop, @prefix-create,
@prefix-create-hwp}
+
+ Before(prefixes.join(',')) do |scenario|
+ prefix = scenario.source_tag_names.first.gsub(/@prefix-/, '')
+ $scenario_prefix = prefix
+ end
+
+ After(prefixes.join(',')) do |scenario|
+ $scenario_prefix = nil
+ end
+
+ include Rack::Test::Methods
+end
+
diff --git a/tests/mock/99_rake.feature b/tests/mock/99_rake.feature
new file mode 100644
index 0000000..c4362c5
--- /dev/null
+++ b/tests/mock/99_rake.feature
@@ -0,0 +1,7 @@
+Feature: Running rake tasks
+
+ Scenario: I want to build Deltacloud API gem
+ Given I have a clean /pkg directory
+ When I run a 'package' task
+ Then I should see a gem file inside pkg directory
+ And I should see a tgz file inside pkg directory
diff --git a/tests/mock/api.feature b/tests/mock/api.feature
new file mode 100644
index 0000000..8c4ddd2
--- /dev/null
+++ b/tests/mock/api.feature
@@ -0,0 +1,41 @@
+Feature: Accessing API entry points
+
+ Scenario: API driver and version
+ Given URI /api exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'api'
+ And this element should have attribute 'driver' with value 'mock'
+ And this element should have attribute 'version' with value '1.0'
+
+ Scenario: List of entry points
+ Given URI /api exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get list of valid entry points:
+ | realms |
+ | instances |
+ | images |
+ | instance_states |
+ | hardware_profiles |
+ | storage_snapshots |
+ | storage_volumes |
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Following entry points
+ Given URI /api exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get list of valid entry points
+ And each link should have 'rel' attribute with valid name
+ And each link should have 'href' attribute with valid URL
+ When client follow this attribute
+ Then client should get a valid response
+
+ Scenario: Instance features
+ Given URI /api exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get list of features inside 'instances':
+ | hardware_profiles |
+ | user_name |
diff --git a/tests/mock/hardware_profiles.feature b/tests/mock/hardware_profiles.feature
new file mode 100644
index 0000000..f10bb13
--- /dev/null
+++ b/tests/mock/hardware_profiles.feature
@@ -0,0 +1,29 @@
+Feature: Accessing hardware profiles
+
+ Scenario: I want to get list of all hardware profiles
+ Given URI /api/hardware_profiles exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'hardware-profiles'
+ And this URI should be available in XML, HTML, JSON format
+
+ Scenario: I want to show hardware profile details
+ Given URI /api/hardware_profiles exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'hardware-profiles'
+ When client want to show 'm1-large' hardware-profile
+ And client should get this hardware-profile
+ And it should have a href attribute
+ And it should have a fixed property 'cpu'
+ And it should have a range property 'memory'
+ And it should have a enum property 'storage'
+ And this URI should be available in XML, HTML, JSON format
+
+ Scenario: Filtering images by architecture
+ Given URI /api/hardware_profiles exists
+ And authentification is required for this URI
+ When client access this URI with parameters:
+ | architecture | i386 |
+ Then client should get some hardware-profiles
+ And each hardware-profile should have 'architecture' attribute set to
'i386'
diff --git a/tests/mock/images.feature b/tests/mock/images.feature
new file mode 100644
index 0000000..50c3570
--- /dev/null
+++ b/tests/mock/images.feature
@@ -0,0 +1,59 @@
+Feature: Listing and showing images
+
+ Scenario: Listing available images
+ Given URI /api/images exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'images'
+ And this element contains some images
+ And each image should have:
+ | id |
+ | name |
+ | description |
+ | architecture |
+ | owner_id |
+ And each image should have 'href' attribute with valid URL
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Following image href attribute
+ Given URI /api/images exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'images'
+ And this element contains some images
+ When client want to show first image
+ Then client should follow href attribute in image
+ And client should get valid response with requested image
+ And this image should have:
+ | id |
+ | name |
+ | description |
+ | architecture |
+ | owner_id |
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Filtering images by owner_id
+ Given URI /api/images exists
+ And authentification is required for this URI
+ When client access this URI with parameters:
+ | owner_id | fedoraproject |
+ Then client should get some images
+ And each image should have 'owner_id' attribute set to
'fedoraproject'
+
+ Scenario: Filtering images by architecture
+ Given URI /api/images exists
+ And authentification is required for this URI
+ When client access this URI with parameters:
+ | architecture | i386 |
+ Then client should get some images
+ And each image should have 'architecture' attribute set to 'i386'
+
+ Scenario: Filtering images by architecture and owner_id
+ Given URI /api/images exists
+ And authentification is required for this URI
+ When client access this URI with parameters:
+ | architecture | i386 |
+ | owner_id | fedoraproject |
+ Then client should get some images
+ And each image should have 'architecture' attribute set to 'i386'
+ And each image should have 'owner_id' attribute set to
'fedoraproject'
diff --git a/tests/mock/instance_states.feature b/tests/mock/instance_states.feature
new file mode 100644
index 0000000..3008ef0
--- /dev/null
+++ b/tests/mock/instance_states.feature
@@ -0,0 +1,36 @@
+Feature: Instance states and transitions
+
+ Scenario: Getting list of states
+ Given URI /api/instance_states exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'states'
+ And this element contains some states
+ And this URI should be available in XML, JSON, HTML format
+
+
+ Scenario: State names
+ Given URI /api/instance_states exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'states'
+ And states element contains some states
+ And each state should have 'name' attribute
+ And first state should have 'name' attribute set to 'start'
+ And last state should have 'name' attribute set to 'finish'
+
+ Scenario: Transitions
+ Given URI /api/instance_states exists
+ And authentification is not required for this URI
+ When client access this URI
+ Then client should get root element 'states'
+ And states element contains some states
+ And some states should have transitions
+ And each transitions should have 'to' attribute
+
+ Scenario: State diagram
+ Given URI /api/instance_states exists
+ And authentification is not required for this URI
+ When client access this URI
+ And client wants PNG format
+ Then client should get PNG image
diff --git a/tests/mock/instances.feature b/tests/mock/instances.feature
new file mode 100644
index 0000000..64828ea
--- /dev/null
+++ b/tests/mock/instances.feature
@@ -0,0 +1,165 @@
+Feature: Managing instances
+
+ Scenario: Listing current instances
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ And each instance should have:
+ | id |
+ | name |
+ | owner_id |
+ | image |
+ | realm |
+ | state |
+ | hardware-profile |
+ | actions |
+ | public-addresses |
+ | private-addresses |
+ And each instance should have 'href' attribute with valid URL
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Filtering instances by state
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI with parameters:
+ | state | RUNNING |
+ Then client should get some instances
+ And each instance should have 'state' attribute set to 'RUNNING'
+
+ Scenario: Get details about first instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client want to show first instance
+ Then client follow href attribute in first instance
+ Then client should get this instance
+ And this instance should have:
+ | id |
+ | name |
+ | owner_id |
+ | image |
+ | realm |
+ | state |
+ | hardware-profile |
+ | actions |
+ | public-addresses |
+ | private-addresses |
+
+ Scenario: Following image href in instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client follow image href attribute in first instance
+ Then client should get valid image
+
+ Scenario: Following realm href in instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client follow realm href attribute in first instance
+ Then client should get valid realm
+
+ Scenario: Following hardware profile href in instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client follow hardware-profile href attribute in first instance
+ Then client should get valid hardware-profile
+
+ Scenario: Instance actions
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ And each instance should have actions
+ And each actions should have some links
+ And each link should have valid href attribute
+ And each link should have valid method attribute
+ And each link should have valid rel attribute
+
+ Scenario: Reboot instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client want to 'reboot' first instance
+ And client follow link in actions
+ Then client should get first instance
+ And this instance should be in 'RUNNING' state
+
+ Scenario: Stop instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client want to 'stop' first instance
+ And client follow link in actions
+ Then client should get first instance
+ And this instance should be in 'STOPPED' state
+
+ Scenario: Start instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'instances'
+ And this element contains some instances
+ When client want to 'start' first instance
+ And client follow link in actions
+ Then client should get first instance
+ And this instance should be in 'RUNNING' state
+
+ Scenario: Basic instance creation
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client want to create a new instance
+ Then client should choose first image
+ When client request for a new instance
+ Then new instance should be created
+ And this instance should have chosed image
+ And this instance should be in 'RUNNING' state
+ And this instance should have valid id
+ And this instance should have name
+
+ Scenario: Choosing hardware profile for instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client want to create a new instance
+ Then client should choose first image
+ And client choose last hardware profile
+ When client request for a new instance
+ Then new instance should be created
+ And this instance should have chosed image
+ And this instance should be in 'RUNNING' state
+ And this instance should have valid id
+ And this instance should have last hardware profile
+ And this instance should have name
+
+ Scenario: Create instance using HTML form
+ Given URI /api/instances/new exists in HTML format
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get HTML form
+
+ Scenario: Destroying created instance
+ Given URI /api/instances exists
+ And authentification is required for this URI
+ When client want to 'stop' created instance
+ And client follow link in actions
+ Then client should get created instance
+ And this instance should be in 'STOPPED' state
+ When client want to 'destroy' created instance
+ And client follow link in actions
+ And this instance should be destroyed
diff --git a/tests/mock/realms.feature b/tests/mock/realms.feature
new file mode 100644
index 0000000..a89173b
--- /dev/null
+++ b/tests/mock/realms.feature
@@ -0,0 +1,31 @@
+Feature: Accessing realms
+
+ Scenario: Getting list of available realms
+ Given URI /api/realms exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'realms'
+ And this element contains some realms
+ And each realm should have:
+ | id |
+ | name |
+ | state |
+ | limit |
+ And each realm should have 'href' attribute with valid URL
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Following realm href attribute
+ Given URI /api/realms exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'realms'
+ And this element contains some realms
+ When client want to show first realm
+ Then client should follow href attribute in realm
+ And client should get valid response with requested realm
+ And this realm should have:
+ | id |
+ | name |
+ | state |
+ | limit |
+ And this URI should be available in XML, JSON, HTML format
diff --git a/tests/mock/step_definitions/api_steps.rb
b/tests/mock/step_definitions/api_steps.rb
new file mode 100644
index 0000000..9a30c3d
--- /dev/null
+++ b/tests/mock/step_definitions/api_steps.rb
@@ -0,0 +1,103 @@
+Given /^URI ([\w\/\-_]+) exists$/ do |uri|
+ get uri, {}
+ last_response.status.should_not == 404
+ last_response.status.should_not == 500
+ @uri = uri
+end
+
+Given /^URI ([\w\/\-_]+) exists in (.+) format$/ do |uri, format|
+ @uri = "#{uri}.#{format.downcase}"
+ get @uri, {}
+ last_response.status.should_not == 404
+ last_response.status.should_not == 500
+end
+
+Given /^authentification is not required for this URI$/ do
+ last_response.status.should_not == 401
+end
+
+When /^client access this URI$/ do
+ get @uri, {}
+ last_response.status.should_not == 404
+end
+
+Then /^client should get root element '(.+)'$/ do |element|
+ @last_element = output_xml.xpath('/'+element).first
+ @last_element.should_not be_nil
+ @last_element.name.should == element
+end
+
+Then /^this element should have attribute '(.+)' with value '(.+)'$/ do
|atr, val|
+ @last_element[atr.to_sym].should == val
+end
+
+Then /^client should get list of valid entry points:$/ do |table|
+ @entry_points = table.raw.flatten.sort
+ links = []
+ output_xml.xpath('/api/link').each do |entry_point|
+ links << entry_point['rel']
+ end
+ @entry_points.should == links.sort
+end
+
+Then /^this URI should be available in (.+) format$/ do |formats|
+ @no_header = true
+ formats.split(',').each do |format|
+ get "#{(a)uri}.#{format.strip.downcase}", {}
+ last_response.status.should == 200
+ end
+ @no_header = false
+end
+
+Then /^client should get list of valid entry points$/ do
+ links = []
+ output_xml.xpath('/api/link').each do |entry_point|
+ links << entry_point['rel']
+ end
+ @entry_points.should == links.sort
+end
+
+Then /^each (\w+) should have '(.+)' attribute with valid (.+)$/ do |el, attr,
t|
+ case el
+ when 'link':
+ path = '/api/link'
+ when 'image':
+ path = '/images/image'
+ end
+ output_xml.xpath(path).each do |entry_point|
+ @entry_points.include?(entry_point[attr]).should == true if t=='name'
+ if t=='URL'
+ entry_point[:href].should_not be_nil
+ end
+ end
+ @last_attribute = attr
+end
+
+Then /^each ([\w\-]+) should have '(.+)' attribute set to '(.+)'$/ do
|el, attr, v|
+ case el
+ when 'image':
+ path = "/image/images"
+ end
+ output_xml.xpath(path).each do |element|
+ element[attr].should == v
+ end
+end
+
+When /^client follow this attribute$/ do
+ output_xml.xpath('/api/link').each do |entry_point|
+ get entry_point[@last_attribute], {}
+ end
+end
+
+Then /^client should get a valid response$/ do
+ last_response.status.should_not == 500
+end
+
+Then /^client should get list of features inside '(.+)':$/ do |element,table|
+ features = table.raw.flatten.sort
+ instance_features = []
+
output_xml.xpath('/api/link[(a)rel="'+element+'"]/feature').each
do |feature|
+ instance_features << feature[:name]
+ end
+ features.should == instance_features.sort
+end
diff --git a/tests/mock/step_definitions/hardware_profiles_steps.rb
b/tests/mock/step_definitions/hardware_profiles_steps.rb
new file mode 100644
index 0000000..db1828b
--- /dev/null
+++ b/tests/mock/step_definitions/hardware_profiles_steps.rb
@@ -0,0 +1,25 @@
+Then /^it should have a (\w+) attribute$/ do |name|
+ attr = output_xml.xpath('/hardware-profile').first[name]
+ attr.should_not be_nil
+end
+
+Then /^it should have a (\w+) property '(.+)'$/ do |kind, name|
+ props = output_xml.xpath("/hardware-profile/property[@name =
'#{name}']")
+ props.size.should == 1
+ prop = props.first
+ prop['kind'].should == kind
+ prop['unit'].should_not be_nil
+ if kind == 'range'
+ ranges = prop.xpath('range')
+ ranges.size.should == 1
+ range = ranges.first
+ range['first'].should_not be_nil
+ range['last'].should_not be_nil
+ end
+ if kind == 'enum'
+ enums = prop.xpath('enum')
+ enums.size.should == 1
+ enums.first.xpath('entry').size.should_not == 0
+ end
+end
+
diff --git a/tests/mock/step_definitions/images_steps.rb
b/tests/mock/step_definitions/images_steps.rb
new file mode 100644
index 0000000..fc01364
--- /dev/null
+++ b/tests/mock/step_definitions/images_steps.rb
@@ -0,0 +1,83 @@
+Given /^authentification is required for this URI$/ do
+ authorize CONFIG[:username], CONFIG[:password]
+ get @uri, {}
+ last_response.status.should == 200
+end
+
+Then /^this element contains some (.+)$/ do |items|
+ item = items.singularize
+ output_xml.xpath("/#{(a)last_element.name}/#{item}").size.should > 0
+end
+
+Then /^each ([\w\-]+) should have:$/ do |item, table|
+ properties = table.raw.flatten.sort
+ output_xml.xpath("/#{(a)last_element.name}/#{item}").each do |element|
+ childrens = (element > '*').collect { |c| c.name }
+ childrens.sort.should == properties
+ end
+end
+
+Then /^this ([\w\-]+) should have:$/ do |item, table|
+ properties = table.raw.flatten.sort
+ output_xml.xpath("/#{item}").each do |element|
+ childrens = (element > '*').collect { |c| c.name }
+ childrens.sort.should == properties
+ end
+end
+
+When /^client want to show first (.+)$/ do |element|
+ case element
+ when 'image':
+ path = '/images/image'
+ when 'instance':
+ path = '/instances/instance'
+ when 'realm':
+ path = '/realms/realm'
+ when 'hardware-profile'
+ path = '/hardware-profiles/hardware-profile'
+ when 'storage-volume':
+ path = '/storage-volumes/storage-volume'
+ when 'storage-snapshot':
+ path = '/storage-snapshots/storage-snapshot'
+ end
+ @element = output_xml.xpath(path).first
+ @element.should_not be_nil
+end
+
+When /^client want to show '(.+)' (.+)$/ do |id, el|
+ @uri = "/api/#{el.pluralize.tr('-', '_')}/#{id}"
+ get @uri, {}
+ @element = output_xml.xpath("/#{el}").first
+ @element.should_not be_nil
+end
+
+Then /^client follow (\w+) attribute in first (.+)$/ do |attr, el|
+ url = output_xml.xpath("/#{el.pluralize}/#{el}").first[:href]
+ url.should_not be_nil
+ get url, {}
+end
+
+Then /^client should get this (.+)$/ do |el|
+ last_response.status.should == 200
+end
+
+
+Then /^client should follow href attribute in (\w+)$/ do |element|
+ get @element[:href], {}
+end
+
+Then /^client should get valid response with requested (\w+)$/ do |element|
+ last_response.status.should == 200
+ output_xml.xpath('/'+element+'/id').first.text.should ==
@element.xpath('id').text
+end
+
+When /^client access this URI with parameters:$/ do |table|
+ params = {}
+ table.raw.each { |i| params[i[0]]=i[1] }
+ get @uri, params
+end
+
+Then /^client should get some ([\w\-]+)$/ do |elements|
+ last_response.status.should == 200
+ output_xml.xpath('/'+elements+'/'+elements.singularize).size.should
> 0
+end
diff --git a/tests/mock/step_definitions/instance_states_steps.rb
b/tests/mock/step_definitions/instance_states_steps.rb
new file mode 100644
index 0000000..a587e5d
--- /dev/null
+++ b/tests/mock/step_definitions/instance_states_steps.rb
@@ -0,0 +1,34 @@
+Then /^states element contains some states$/ do
+ output_xml.xpath('/states/state').size.should > 0
+end
+
+Then /^each state should have '(.+)' attribute$/ do |attr|
+ output_xml.xpath('/states/state').each do |state|
+ state[attr].should_not be_nil
+ end
+end
+
+Then /^(\w+) state should have '(.+)' attribute set to '(\w+)'$/ do |pos,
attr, value|
+ output_xml.xpath('/states/state').first[attr].should==value if
pos=='first'
+ output_xml.xpath('/states/state').last[attr].should==value if
pos=='last'
+end
+
+Then /^some states should have transitions$/ do
+ @transitions = output_xml.xpath('/states/state/transition')
+ @transitions.size.should > 0
+end
+
+Then /^each transitions should have 'to' attribute$/ do
+ @transitions.each do |t|
+ t[:to].should_not be_nil
+ end
+end
+
+When /^client wants (\w+) format$/ do |format|
+ get "#{(a)uri}.#{format.downcase}", {}
+end
+
+Then /^client should get PNG image$/ do
+ last_response.status.should == 200
+ last_response.headers['Content-Type'].should == 'image/png'
+end
diff --git a/tests/mock/step_definitions/instances_steps.rb
b/tests/mock/step_definitions/instances_steps.rb
new file mode 100644
index 0000000..8ec6526
--- /dev/null
+++ b/tests/mock/step_definitions/instances_steps.rb
@@ -0,0 +1,121 @@
+When /^client follow ([\w\-]+) href attribute in first instance$/ do |element|
+ get output_xml.xpath('/instances/instance[1]/'+element).first[:href], {}
+end
+
+Then /^client should get valid ([\w\-]+)$/ do |element|
+ last_response.status.should == 200
+ output_xml.xpath("/#{element}").first.should_not be_nil
+end
+
+Then /^each instance should have actions$/ do
+ output_xml.xpath('/instances/instance').each do |instance|
+ instance.xpath('actions').first.should_not be_nil
+ end
+end
+
+Then /^each actions should have some links$/ do
+ output_xml.xpath('/instances/instance').each do |instance|
+ instance.xpath('actions/link').first.should_not be_nil
+ end
+end
+
+Then /^each link should have valid (\w+) attribute$/ do |attr|
+ output_xml.xpath('/instances/instance').each do |instance|
+ instance.xpath('actions/link').first[attr].should_not be_nil
+ end
+end
+
+When /^client want to '(\w+)' first instance$/ do |action|
+ @action = action
+ @instance = output_xml.xpath('/instances/instance[1]').first
+end
+
+When /^client follow link in actions$/ do
+ unless @instance_url
+ l = output_xml.xpath("/instances/instance[1]/actions/link[@rel =
'#{(a)action}']").first
+ else
+ l =
@instance.xpath('actions/link[@rel="'+(a)action+'"]').first
+ end
+ unless @action=='destroy'
+ post l[:href], { :id => @instance.xpath('id').first.text }
+ else
+ delete l[:href], { :id => @instance.xpath('id').first.text }
+ end
+ last_response.status.should_not == 500
+end
+
+Then /^client should get first instance$/ do
+ output_xml.xpath('/instance/id').first.should_not be_nil
+ #output_xml.xpath('/instance/id').first.text.should ==
@instance.xpath('id').first.text
+end
+
+Then /^this instance should be in '(.+)' state$/ do |state|
+ output_xml.xpath('/instance/state').first.text.should == state
+end
+
+When /^client want to create a new instance$/ do
+end
+
+Then /^client should choose first image$/ do
+ get '/api/images', {}
+ @image = output_xml.xpath('/images/image').first
+ @image.should_not be_nil
+end
+
+When /^client request for a new instance$/ do
+ params = {
+ :image_id => @image.xpath('id').first.text
+ }
+ params[:hwp_id] = @hwp_id if @hwp_id
+ post "#{@uri}", params
+ last_response.status.should == 201
+ @instance_url = last_response.headers['Location']
+end
+
+Then /^new instance should be created$/ do
+ get @instance_url, {}
+ last_response.status.should == 200
+end
+
+Then /^this instance should have chosed image$/ do
+ output_xml.xpath('/instance/image').first[:href].should == @image[:href]
+end
+
+Then /^this instance should have valid id$/ do
+ output_xml.xpath('instance/id').first.should_not be_nil
+end
+
+Then /^this instance should have name$/ do
+ output_xml.xpath('instance/name').first.should_not be_nil
+end
+
+When /^client want to '(\w+)' created instance$/ do |action|
+ get @instance_url, {}
+ last_response.status.should == 200
+ @action = action
+ @instance = output_xml.xpath('/instance')
+end
+
+Then /^client should get created instance$/ do
+ get @instance_url
+end
+
+When /^this instance should be destroyed$/ do
+ # TODO: Fix this bug in mock driver ?
+ #get @instance_url, {}
+ #last_response.status.should == 404
+end
+
+Then /^client should get HTML form$/ do
+ last_response.status.should == 200
+ (last_response.body.strip =~ /^<!DOCTYPE html/).should be_true
+end
+
+When /^client choose last hardware profile$/ do
+ get '/api/hardware_profiles', {}
+ @hwp_id = output_xml.xpath('/hardware-profiles/hardware-profile/id').last.text
+end
+
+Then /^this instance should have last hardware profile$/ do
+ output_xml.xpath('instance/hardware-profile/id').first.text.should == @hwp_id
+end
diff --git a/tests/mock/step_definitions/rake_steps.rb
b/tests/mock/step_definitions/rake_steps.rb
new file mode 100644
index 0000000..c8ea3d9
--- /dev/null
+++ b/tests/mock/step_definitions/rake_steps.rb
@@ -0,0 +1,19 @@
+require 'fileutils'
+require 'rake'
+require 'find'
+
+Given /^I have a clean (.+) directory$/ do |dir|
+ FileUtils.rm_rf dir
+end
+
+When /^I run a '(\w+)' task$/ do |task|
+ @rake = Rake::Application.new
+ Rake.application = @rake
+ load "Rakefile"
+ @task = Rake::Task[task]
+ @task.invoke
+end
+
+Then /^I should see a (\w+) file inside (\w+) directory$/ do |ext, dir|
+ Dir["#{dir}/deltacloud-*.#{ext}"].size.should == 1
+end
diff --git a/tests/mock/storage_snapshots.feature b/tests/mock/storage_snapshots.feature
new file mode 100644
index 0000000..f6f38e5
--- /dev/null
+++ b/tests/mock/storage_snapshots.feature
@@ -0,0 +1,29 @@
+Feature: Accessing storage snapshots
+
+ Scenario: Listing available storage snapshots
+ Given URI /api/storage_snapshots exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'storage-snapshots'
+ And this element contains some storage-snapshots
+ And each storage-volume should have:
+ | id |
+ | created |
+ | storage-volume |
+ And each image should have 'href' attribute with valid URL
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Get details about first volume
+ Given URI /api/storage_snapshots exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'storage-snapshots'
+ And this element contains some storage-snapshots
+ When client want to show first storage-snapshot
+ Then client follow href attribute in first storage-snapshot
+ Then client should get this storage-snapshot
+ And this storage-snapshot should have:
+ | id |
+ | created |
+ | state |
+ | storage-volume |
diff --git a/tests/mock/storage_volumes.feature b/tests/mock/storage_volumes.feature
new file mode 100644
index 0000000..dfca4b0
--- /dev/null
+++ b/tests/mock/storage_volumes.feature
@@ -0,0 +1,33 @@
+Feature: Accessing storage volumes
+
+ Scenario: Listing available storage volumes
+ Given URI /api/storage_volumes exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'storage-volumes'
+ And this element contains some storage-volumes
+ And each storage-volume should have:
+ | id |
+ | created |
+ | capacity |
+ | device |
+ | instance |
+ And each image should have 'href' attribute with valid URL
+ And this URI should be available in XML, JSON, HTML format
+
+ Scenario: Get details about first volume
+ Given URI /api/storage_volumes exists
+ And authentification is required for this URI
+ When client access this URI
+ Then client should get root element 'storage-volumes'
+ And this element contains some storage-volumes
+ When client want to show first storage-volume
+ Then client follow href attribute in first storage-volume
+ Then client should get this storage-volume
+ And this storage-volume should have:
+ | id |
+ | created |
+ | capacity |
+ | device |
+ | instance |
+ | state |
diff --git a/tests/mock/support/env.rb b/tests/mock/support/env.rb
new file mode 100644
index 0000000..bd544d0
--- /dev/null
+++ b/tests/mock/support/env.rb
@@ -0,0 +1,40 @@
+SERVER_DIR = File::expand_path(File::join(File::dirname(__FILE__),
"../../../server"))
+Dir.chdir(SERVER_DIR)
+
+require 'sinatra'
+require 'rack/test'
+require 'nokogiri'
+require '../server/server'
+require 'ap'
+
+Sinatra::Application.set :environment, :test
+Sinatra::Application.set :root, SERVER_DIR
+
+CONFIG = {
+ :username => 'mockuser',
+ :password => 'mockpassword'
+}
+
+World do
+
+ def app
+ @app = Rack::Builder.new do
+ set :logging, true
+ set :raise_errors, true
+ run Sinatra::Application
+ end
+ end
+
+ def output_xml
+ Nokogiri::XML(last_response.body)
+ end
+
+ Before do
+ unless @no_header
+ header 'Accept', 'application/xml'
+ end
+ end
+
+ include Rack::Test::Methods
+end
+
--
1.7.1