You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltacloud.apache.org by dk...@apache.org on 2013/02/21 01:07:38 UTC

git commit: CIMI: system and system_template support for mock driver, with unit tests. Just GET for now, no subcollections

Updated Branches:
  refs/heads/master d3e2719eb -> d0353f795


CIMI: system and system_template support for mock driver, with unit tests.
Just GET for now, no subcollections


Project: http://git-wip-us.apache.org/repos/asf/deltacloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltacloud/commit/d0353f79
Tree: http://git-wip-us.apache.org/repos/asf/deltacloud/tree/d0353f79
Diff: http://git-wip-us.apache.org/repos/asf/deltacloud/diff/d0353f79

Branch: refs/heads/master
Commit: d0353f795d1aa995f3355ce63557a014fd64b2fc
Parents: d3e2719
Author: Dies Koper <di...@fast.au.fujitsu.com>
Authored: Fri Feb 15 21:19:29 2013 +1100
Committer: Dies Koper <di...@fast.au.fujitsu.com>
Committed: Thu Feb 21 11:07:17 2013 +1100

----------------------------------------------------------------------
 server/lib/cimi/collections/system_templates.rb    |   72 ++++++
 server/lib/cimi/collections/systems.rb             |  194 +++++++++++++++
 server/lib/cimi/models.rb                          |    2 +
 server/lib/cimi/models/system.rb                   |   68 +++++
 server/lib/cimi/models/system_template.rb          |   64 +++++
 .../drivers/mock/data/cimi/system/system1.json     |   12 +
 .../drivers/mock/data/cimi/system/system2.json     |   12 +
 .../mock/data/cimi/system_template/template1.json  |   28 ++
 .../drivers/mock/mock_driver_cimi_methods.rb       |   30 +++
 .../cimi/collections/system_templates_test.rb      |   41 +++
 server/tests/cimi/collections/systems_test.rb      |   50 ++++
 11 files changed, 573 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/lib/cimi/collections/system_templates.rb
----------------------------------------------------------------------
diff --git a/server/lib/cimi/collections/system_templates.rb b/server/lib/cimi/collections/system_templates.rb
new file mode 100644
index 0000000..7ab0d3e
--- /dev/null
+++ b/server/lib/cimi/collections/system_templates.rb
@@ -0,0 +1,72 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class SystemTemplates < Base
+
+    set :capability, lambda { |m| driver.respond_to? m }
+
+    collection :system_templates do
+
+      operation :index, :with_capability => :system_templates do
+        description "List all system templates"
+        control do
+          system_templates = CIMI::Model::SystemTemplate.list(self).select_by(params['$select'])
+          respond_to do |format|
+            format.xml { system_templates.to_xml }
+            format.json { system_templates.to_json }
+          end
+        end
+      end
+
+      operation :show, :with_capability => :system_templates do
+        description "Show specific system template"
+        control do
+          system_template = CIMI::Model::SystemTemplate.find(params[:id], self)
+          respond_to do |format|
+            format.xml { system_template.to_xml }
+            format.json { system_template.to_json }
+          end
+        end
+      end
+
+      operation :create, :with_capability => :create_system_template do
+        description "Create new system template"
+        control do
+          if grab_content_type(request.content_type, request.body) == :json
+            new_system_template = CIMI::Model::SystemTemplate.create_from_json(request.body.read, self)
+          else
+            new_system_template = CIMI::Model::SystemTemplate.create_from_xml(request.body.read, self)
+          end
+          headers_for_create new_system_template
+          respond_to do |format|
+            format.json { new_system_template.to_json }
+            format.xml { new_system_template.to_xml }
+          end
+        end
+      end
+
+      operation :destroy, :with_capability => :destroy_system_template do
+        description "Delete a specified system template"
+        control do
+          CIMI::Model::SystemTemplate.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+    end
+
+  end
+end

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/lib/cimi/collections/systems.rb
----------------------------------------------------------------------
diff --git a/server/lib/cimi/collections/systems.rb b/server/lib/cimi/collections/systems.rb
new file mode 100644
index 0000000..ded0aa6
--- /dev/null
+++ b/server/lib/cimi/collections/systems.rb
@@ -0,0 +1,194 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Systems < Base
+
+    set :capability, lambda { |m| driver.respond_to? m }
+
+    collection :systems do
+      description 'List all systems'
+
+      operation :index, :with_capability => :systems do
+        description "List all systems"
+        control do
+          systems = System.list(self).select_by(params['$select']).filter_by(params['$filter'])
+          respond_to do |format|
+            format.xml { systems.to_xml }
+            format.json { systems.to_json }
+          end
+        end
+      end
+
+      operation :show, :with_capability => :systems do
+        description "Show specific system."
+        control do
+          system = System.find(params[:id], self)
+          respond_to do |format|
+            format.xml { system.to_xml }
+            format.json { system.to_json }
+          end
+        end
+      end
+
+      operation :create, :with_capability => :create_system do
+        description "Create a new System entity."
+        control do
+          if grab_content_type(request.content_type, request.body) == :json
+            new_system = System.create_from_json(request.body.read, self)
+          else
+            new_system = System.create_from_xml(request.body.read, self)
+          end
+          headers_for_create new_system
+          respond_to do |format|
+            format.json { new_system.to_json }
+            format.xml { new_system.to_xml }
+          end
+        end
+      end
+
+      operation :destroy, :with_capability => :destroy_system do
+        description "Delete a specified system."
+        control do
+          System.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+      action :stop, :with_capability => :stop_system do
+        description "Stop specific system."
+        param :id,          :string,    :required
+        control do
+          system = System.find(params[:id], self)
+          action = Action.parse(request.body,
+          request.content_type)
+          system.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      action :restart, :with_capability => :reboot_system do
+        description "Restart specific system."
+        param :id,          :string,    :required
+        control do
+          system = System.find(params[:id], self)
+          if  grab_content_type(request.content_type, request.body) == :json
+            action = Action.from_json(request.body.read.gsub("restart", "reboot"))
+          else
+            action = Action.from_xml(request.body.read.gsub("restart", "reboot"))
+          end
+          system.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      action :start, :with_capability => :start_system do
+        description "Start specific system."
+        param :id,          :string,    :required
+        control do
+          system = System.find(params[:id], self)
+          if  grab_content_type(request.content_type, request.body) == :json
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          system.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      action :pause, :with_capability => :pause_system do
+        description "Pause specific system."
+        param :id,          :string,    :required
+        control do
+          system = System.find(params[:id], self)
+          if  grab_content_type(request.content_type, request.body) == :json
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          system.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      action :suspend, :with_capability => :suspend_system do
+        description "Suspend specific system."
+        param :id,          :string,    :required
+        control do
+          system = System.find(params[:id], self)
+          if  grab_content_type(request.content_type, request.body) == :json
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          system.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      #use rabbit subcollections for volumes index/show:
+      collection :volumes, :with_id => :vol_id do
+
+        operation :index, :with_capability => :storage_volumes do
+          description "Retrieve the System's SystemVolumeCollection"
+          control do
+            volumes = CIMI::Model::SystemVolume.collection_for_system(params[:id], self)
+            respond_to do |format|
+              format.json {volumes.to_json}
+              format.xml  {volumes.to_xml}
+            end
+          end
+        end
+
+        operation :show, :with_capability => :storage_volumes do
+          description "Retrieve a System's specific SystemVolume"
+          control do
+            volume = CIMI::Model::SystemVolume.find(params[:id], self, params[:vol_id])
+            respond_to do |format|
+              format.json {volume.to_json}
+              format.xml  {volume.to_xml}
+            end
+          end
+        end
+
+        operation :destroy, :with_capability => :detach_storage_volume do
+          description "Remove/detach a volume from the System's SystemVolumeCollection"
+          control do
+            system_volume = CIMI::Model::SystemVolume.find(params[:id], self, params[:vol_id])
+            location = system_volume.initial_location
+            system_volumes = System.detach_volume(params[:vol_id], location, self)
+            respond_to do |format|
+              format.json{ system_volumes.to_json}
+              format.xml{ system_volumes.to_xml}
+            end
+          end
+        end
+
+      end
+    end
+
+  end
+end

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/lib/cimi/models.rb
----------------------------------------------------------------------
diff --git a/server/lib/cimi/models.rb b/server/lib/cimi/models.rb
index 39beae4..c48b531 100644
--- a/server/lib/cimi/models.rb
+++ b/server/lib/cimi/models.rb
@@ -79,3 +79,5 @@ require_relative './models/address'
 require_relative './models/address_template'
 require_relative './models/forwarding_group'
 require_relative './models/forwarding_group_template'
+require_relative './models/system_template'
+require_relative './models/system'

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/lib/cimi/models/system.rb
----------------------------------------------------------------------
diff --git a/server/lib/cimi/models/system.rb b/server/lib/cimi/models/system.rb
new file mode 100644
index 0000000..c2b94db
--- /dev/null
+++ b/server/lib/cimi/models/system.rb
@@ -0,0 +1,68 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::System < CIMI::Model::Base
+
+  acts_as_root_entity
+
+  text :state
+
+#  collection :systems, :class => CIMI::Model::SystemSystem
+#  collection :machines, :class => CIMI::Model::SystemMachine
+#  collection :credentials, :class => CIMI::Model::SystemCredential
+#  collection :volumes, :class => CIMI::Model::SystemVolume
+#  collection :networks, :class => CIMI::Model::SystemNetwork
+#  collection :network_ports, :class => CIMI::Model::SystemNetworkPort
+#  collection :addresses, :class => CIMI::Model::SystemAddress
+#  collection :forwarding_groups, :class => CIMI::Model::SystemForwardingGroup
+
+#  array :meters do
+#    scalar :href
+#  end
+
+#  href :event_log
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    systems = []
+    if id == :all
+      systems = context.driver.systems(context.credentials, {:env=>context})
+    else
+      system = context.driver.systems(context.credentials, {:env=>context, :id=>id})
+      raise CIMI::Model::NotFound unless system
+      system
+    end
+  end
+
+  def perform(action, context, &block)
+    begin
+      if context.driver.send(:"#{action.name}_system", context.credentials, self.id.split("/").last)
+        block.callback :success
+      else
+        raise "Operation failed to execute on given System"
+      end
+    rescue => e
+      block.callback :failure, e.message
+    end
+  end
+
+  def self.delete!(id, context)
+    context.driver.destroy_system(context.credentials, id)
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/lib/cimi/models/system_template.rb
----------------------------------------------------------------------
diff --git a/server/lib/cimi/models/system_template.rb b/server/lib/cimi/models/system_template.rb
new file mode 100644
index 0000000..f252e28
--- /dev/null
+++ b/server/lib/cimi/models/system_template.rb
@@ -0,0 +1,64 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::SystemTemplate < CIMI::Model::Base
+
+  acts_as_root_entity
+
+  array :component_descriptors do
+    text :name, :description
+    hash :properties
+    text :type
+    #component_template, comprises:
+#    struct :machine_template, :class => CIMI::Model::MachineTemplate
+#    struct :system_template, :class => CIMI::Model::SystemTemplate
+#    struct :credential_template, :class => CIMI::Model::CredentialTemplate
+#    struct :volume_template, :class => CIMI::Model::VolumeTemplate
+#    struct :network_template, :class => CIMI::Model::NetworkTemplate
+#    struct :network_port_template, :class => CIMI::Model::NetworkPortTemplate
+#    struct :forwarding_group_template, :class => CIMI::Model::ForwardingGroupTemplate
+#    struct :address_template, :class => CIMI::Model::AddressTemplate
+    text :quantity
+  end
+
+#  array :meter_templates do
+#    scalar :href
+#  end
+
+#  href :event_log_template
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  class << self
+    def find(id, context)
+      templates = []
+      if id == :all
+        templates = context.driver.system_templates(context.credentials, {:env=>context})
+      else
+        template = context.driver.system_templates(context.credentials, {:env=>context, :id=>id})
+        raise CIMI::Model::NotFound unless template
+        template
+      end
+    end
+
+    def delete!(id, context)
+      context.driver.destroy_system_template(context.credentials, id)
+    end
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/lib/deltacloud/drivers/mock/data/cimi/system/system1.json
----------------------------------------------------------------------
diff --git a/server/lib/deltacloud/drivers/mock/data/cimi/system/system1.json b/server/lib/deltacloud/drivers/mock/data/cimi/system/system1.json
new file mode 100644
index 0000000..689ba60
--- /dev/null
+++ b/server/lib/deltacloud/drivers/mock/data/cimi/system/system1.json
@@ -0,0 +1,12 @@
+{ "id": "http://cimi.example.org/systems/system1",
+  "name": "system1",
+  "description": "the first system",
+  "created": "Fri Feb 08 15:25:41 EET 2013",
+  "state": "STOPPED",
+  "machines": { "href": "http://cimi.example.org/systems/system1/machines"},
+  "networks": { "href": "http://cimi.example.org/systems/system1/networks"},
+  "operations": [
+    { "rel": "edit", "href": "http://cimi.example.org/systems/system1" },
+    { "rel": "delete", "href": "http://cimi.example.org/systems/system1" }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/lib/deltacloud/drivers/mock/data/cimi/system/system2.json
----------------------------------------------------------------------
diff --git a/server/lib/deltacloud/drivers/mock/data/cimi/system/system2.json b/server/lib/deltacloud/drivers/mock/data/cimi/system/system2.json
new file mode 100644
index 0000000..4062fb0
--- /dev/null
+++ b/server/lib/deltacloud/drivers/mock/data/cimi/system/system2.json
@@ -0,0 +1,12 @@
+{ "id": "http://cimi.example.org/systems/system2",
+  "name": "system2",
+  "description": "the second system",
+  "created": "Fri Feb 08 15:25:41 EET 2013",
+  "state": "STOPPED",
+  "machines": { "href": "http://cimi.example.org/systems/system2/machines"},
+  "networks": { "href": "http://cimi.example.org/systems/system2/networks"},
+  "operations": [
+    { "rel": "edit", "href": "http://cimi.example.org/systems/system2" },
+    { "rel": "delete", "href": "http://cimi.example.org/systems/system2" }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/lib/deltacloud/drivers/mock/data/cimi/system_template/template1.json
----------------------------------------------------------------------
diff --git a/server/lib/deltacloud/drivers/mock/data/cimi/system_template/template1.json b/server/lib/deltacloud/drivers/mock/data/cimi/system_template/template1.json
new file mode 100644
index 0000000..495fc24
--- /dev/null
+++ b/server/lib/deltacloud/drivers/mock/data/cimi/system_template/template1.json
@@ -0,0 +1,28 @@
+{ "id": "http://cimi.example.org/system_templates/template1",
+  "name": "template1",
+  "description": "A mock system template",
+  "created": "Fri Feb 08 12:15:15 EET 2013",
+  "componentDescriptors": [
+    { "name": "my machine",
+      "type": "http://schemas.dmtf.org/cimi/1/Machine",
+      "description": "an inline mock machine template",
+      "machineTemplate": {
+        "name": "machine in mock system",
+        "description": "machine in system",
+        "machineConfig": { "href": "http://example.com/configs/m1-small" },
+        "machineImage": { "href": "http://example.com/images/img1" }
+      }
+    },
+    { "name": "my network",
+      "type": "http://schemas.dmtf.org/cimi/1/Network",
+      "description": "a reference to an existing mock network template",
+      "networkTemplate": {
+        "href": "http://cimi.example.org/network_templates/template1"
+      }
+    }
+  ],
+  "operations": [
+    { "rel": "edit", "href": "http://cimi.example.org/system_templates/template1" },
+    { "rel": "delete", "href": "http://cimi.example.org/system_templates/template1" }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
----------------------------------------------------------------------
diff --git a/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb b/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
index e410c5a..1180243 100644
--- a/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
@@ -21,6 +21,36 @@ module Deltacloud::Drivers::Mock
 
   class MockDriver < Deltacloud::BaseDriver
 
+    def systems(credentials, opts={})
+      check_credentials(credentials)
+      if opts[:id].nil?
+        systems = @client.load_all_cimi(:system).map{|sys| CIMI::Model::System.from_json(sys)}
+        systems.map{|sys|convert_cimi_mock_urls(:system, sys ,opts[:env])}.flatten
+      else
+        begin
+          system = CIMI::Model::System.from_json(@client.load_cimi(:system, opts[:id]))
+          convert_cimi_mock_urls(:system, system, opts[:env])
+        rescue Errno::ENOENT
+          nil
+        end
+      end
+    end
+
+    def system_templates(credentials, opts={})
+      check_credentials(credentials)
+      if opts[:id].nil?
+        system_templates = @client.load_all_cimi(:system_template).map{|sys_templ| CIMI::Model::SystemTemplate.from_json(sys_templ)}
+        system_templates.map{|sys_templ|convert_cimi_mock_urls(:system_template, sys_templ, opts[:env])}.flatten
+      else
+        begin
+          system_template = CIMI::Model::SystemTemplate.from_json(@client.load_cimi(:system_template, opts[:id]))
+          convert_cimi_mock_urls(:system_template, system_template, opts[:env])
+        rescue Errno::ENOENT
+          nil
+        end
+      end
+    end
+
     def networks(credentials, opts={})
       check_credentials(credentials)
       if opts[:id].nil?

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/tests/cimi/collections/system_templates_test.rb
----------------------------------------------------------------------
diff --git a/server/tests/cimi/collections/system_templates_test.rb b/server/tests/cimi/collections/system_templates_test.rb
new file mode 100644
index 0000000..a9801f7
--- /dev/null
+++ b/server/tests/cimi/collections/system_templates_test.rb
@@ -0,0 +1,41 @@
+require 'rubygems'
+require 'require_relative' if RUBY_VERSION < '1.9'
+require 'minitest/autorun'
+require_relative './common.rb'
+
+describe CIMI::Collections::SystemTemplates do
+
+  before do
+    def app; run_frontend(:cimi) end
+    authorize 'mockuser', 'mockpassword'
+    @collection = CIMI::Collections.collection(:system_templates)
+  end
+
+  it 'has index operation' do
+    @collection.operation(:index).must_equal Sinatra::Rabbit::SystemTemplatesCollection::IndexOperation
+  end
+
+  it 'has show operation' do
+    @collection.operation(:show).must_equal Sinatra::Rabbit::SystemTemplatesCollection::ShowOperation
+  end
+
+  it 'returns list of system templates in various formats with index operation' do
+    formats.each do |format|
+      header 'Accept', format
+      get root_url + '/system_templates'
+      status.must_equal 200
+    end
+  end
+
+  it 'should allow to retrieve the single system template' do
+    get root_url '/system_templates/template1'
+    status.must_equal 200
+    xml.root.name.must_equal 'SystemTemplate'
+  end
+
+  it 'should not return non-existing system_template' do
+    get root_url '/system_templates/unknown-system_template'
+    status.must_equal 404
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/d0353f79/server/tests/cimi/collections/systems_test.rb
----------------------------------------------------------------------
diff --git a/server/tests/cimi/collections/systems_test.rb b/server/tests/cimi/collections/systems_test.rb
new file mode 100644
index 0000000..2e650fd
--- /dev/null
+++ b/server/tests/cimi/collections/systems_test.rb
@@ -0,0 +1,50 @@
+require 'rubygems'
+require 'require_relative' if RUBY_VERSION < '1.9'
+require 'minitest/autorun'
+require_relative './common.rb'
+
+describe CIMI::Collections::Systems do
+
+  before do
+    def app; run_frontend(:cimi) end
+    authorize 'mockuser', 'mockpassword'
+    @collection = CIMI::Collections.collection(:systems)
+  end
+
+  it 'has index operation' do
+    @collection.operation(:index).must_equal Sinatra::Rabbit::SystemsCollection::IndexOperation
+  end
+
+  it 'has show operation' do
+    @collection.operation(:show).must_equal Sinatra::Rabbit::SystemsCollection::ShowOperation
+  end
+
+  it 'returns list of systems in various formats with index operation' do
+    formats.each do |format|
+      header 'Accept', format
+      get root_url + '/systems'
+      status.must_equal 200
+    end
+  end
+
+  it 'should allow to retrieve the single system' do
+    get root_url '/systems/system1'
+    status.must_equal 200
+    xml.root.name.must_equal 'System'
+  end
+
+  it 'should have legal status' do
+    get root_url '/systems'
+    status.must_equal 200
+    (xml/'Collection/System').each do |s|
+      (s/'state').wont_be_empty
+      (s/'state').inner_text.must_equal 'STOPPED'
+    end
+  end
+
+  it 'should not return non-existing system' do
+    get root_url '/systems/unknown-system'
+    status.must_equal 404
+  end
+
+end