Merge branch 'master' of github.com:NOPping/gstack
diff --git a/.gitignore b/.gitignore
index 5a2be01..c5815a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
*.py[cod]
*~
+*.db
# C extensions
*.so
@@ -26,6 +27,7 @@
# Unit test / coverage reports
.coverage
+cover
.tox
nosetests.xml
diff --git a/.travis.yml b/.travis.yml
index d874e9d..d799879 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,9 +4,11 @@
install:
- pip install pylint
- pip install pep8
+ - pip install coveralls
- pip install -e . --use-mirrors
script:
- pep8 --ignore=E501 *.py gstack
- pylint --rcfile=pylint.rc *.py gstack
-
-# Force travis-ci build
+ - nosetests --with-coverage --cover-erase --cover-package=gstack
+after_success:
+ - coveralls
diff --git a/README.rst b/README.rst
index af6f280..a9190a5 100644
--- a/README.rst
+++ b/README.rst
@@ -134,6 +134,43 @@
Sandbox-simulator UP None scheduled
================== ======== ====================
+Running The Tests
+##################
+
+To run the included tests the following software is required:
+
+ pep8
+
+ pylint
+
+ nose
+
+ mock
+
+ coverage
+
+These can be installed via the Python Package Index:
+
+ pip install pep8 pylint nose mock coverage
+
+Tests can be executed from the root of the code base as follows:
+
+Style Check
+___________
+
+ pep8 --ignore=E501 *.py gstack
+
+Lint
+____
+
+ pylint --rcfile=pylint.rc *.py gstack
+
+Unit Tests
+___________
+
+ nosetests --with-coverage --cover-erase --cover-package=gstack --cover-html
+
+A HTML base coverage report will be placed in ./cover
Trouble shooting
#################
diff --git a/gstack/__init__.py b/gstack/__init__.py
index 2627d2b..acc141d 100644
--- a/gstack/__init__.py
+++ b/gstack/__init__.py
@@ -36,10 +36,15 @@
return config_file
-def configure_app():
- config_file = _load_config_file()
- app.config.from_pyfile(config_file)
+def configure_app(settings=None):
app.config['DATA'] = os.path.abspath(os.path.dirname(__file__)) + '/data'
+
+ if settings:
+ app.config.from_object(settings)
+ else:
+ config_file = _load_config_file()
+ app.config.from_pyfile(config_file)
+
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + \
os.path.join(app.config['DATA'], 'app.db')
diff --git a/gstack/controllers/disks.py b/gstack/controllers/disks.py
index 4c8d8a4..0743a48 100644
--- a/gstack/controllers/disks.py
+++ b/gstack/controllers/disks.py
@@ -204,6 +204,7 @@
func_route = url_for(
'getdisk',
projectid=projectid,
+ zone=zone,
disk=disk
)
return errors.resource_not_found(func_route)
diff --git a/gstack/controllers/firewalls.py b/gstack/controllers/firewalls.py
index ce162e4..34fb736 100755
--- a/gstack/controllers/firewalls.py
+++ b/gstack/controllers/firewalls.py
@@ -26,38 +26,39 @@
def _cloudstack_securitygroup_to_gce(response_item):
- rules = response_item['ingressrule']
- allowed = []
- sourceranges = []
- for rule in rules:
- ports = []
- for i in range(rule['startport'], rule['endport'] + 1):
- ports.append(str(i))
- allowed.append({
- "IPProtocol": rule['protocol'],
- "ports": ports
+ if 'ingressrule' in response_item:
+ rules = response_item['ingressrule']
+ allowed = []
+ sourceranges = []
+ for rule in rules:
+ ports = []
+ if 'startport' in rule:
+ for i in range(rule['startport'], rule['endport'] + 1):
+ ports.append(str(i))
+ allowed.append({
+ "IPProtocol": rule['protocol'],
+ "ports": ports
+ })
+ if 'cidr' in rule.keys():
+ sourceranges.append(rule['cidr'])
+ return ({
+ "kind": "compute#firewall",
+ "selfLink": '',
+ "id": response_item['id'],
+ "creationTimestamp": '',
+ "name": response_item['name'],
+ "description": response_item['description'],
+ "network": '',
+ "sourceRanges": sourceranges,
+ "sourceTags": [
+ ''
+ ],
+ "targetTags": response_item['tags'],
+ "allowed": allowed
})
- if 'cidr' in rule.keys():
- sourceranges.append(rule['cidr'])
- return ({
- "kind": "compute#firewall",
- "selfLink": '',
- "id": response_item['id'],
- "creationTimestamp": '',
- "name": response_item['name'],
- "description": response_item['description'],
- "network": '',
- "sourceRanges": sourceranges,
- "sourceTags": [
- ''
- ],
- "targetTags": response_item['tags'],
- "allowed": allowed
- })
-@app.route('/compute/v1/projects/<projectid>/global/firewalls',
- methods=['GET'])
+@app.route('/compute/v1/projects/<projectid>/global/firewalls', methods=['GET'])
@authentication.required
def listsecuritygroups(projectid, authorization):
command = 'listSecurityGroups'
@@ -121,7 +122,7 @@
json.dumps(cloudstack_response, indent=4, separators=(',', ': '))
)
- if cloudstack_response['listsecuritygroupsresponse']:
+ if cloudstack_response['listsecuritygroupsresponse']['securitygroup']:
response_item = cloudstack_response[
'listsecuritygroupsresponse']['securitygroup'][0]
firewall = _cloudstack_securitygroup_to_gce(response_item)
diff --git a/gstack/controllers/index.py b/gstack/controllers/index.py
index 6d76357..293c6ac 100755
--- a/gstack/controllers/index.py
+++ b/gstack/controllers/index.py
@@ -28,8 +28,7 @@
with open(app.config['DATA'] + '/v1.json') as template:
discovery_template = json.loads(template.read())
- discovery_template[
- 'baseUrl'] = helper.get_root_url() + '/' + app.config['PATH']
+ discovery_template['baseUrl'] = helper.get_root_url() + '/' + app.config['PATH']
discovery_template['basePath'] = '/' + app.config['PATH']
discovery_template['rootUrl'] = helper.get_root_url() + '/'
discovery_template['servicePath'] = app.config['PATH']
diff --git a/gstack/controllers/instances.py b/gstack/controllers/instances.py
index f2bee6d..032ba0e 100755
--- a/gstack/controllers/instances.py
+++ b/gstack/controllers/instances.py
@@ -118,17 +118,17 @@
response['disks'] = []
networking = {}
- if cloudstack_response['securitygroup']:
+ accessconfig = {}
+ if 'securitygroup' in cloudstack_response:
networking['network'] = cloudstack_response['securitygroup'][0]['name']
networking['networkIP'] = cloudstack_response['nic'][0]['ipaddress']
networking['name'] = cloudstack_response['nic'][0]['id']
+ accessconfig['natIP'] = cloudstack_response['nic'][0]['ipaddress']
networking['accessConfigs'] = []
- accessconfig = {}
accessconfig['kind'] = 'compute#accessConfig'
accessconfig['type'] = 'ONE_TO_ONE_NAT'
accessconfig['name'] = 'External NAT'
- accessconfig['natIP'] = cloudstack_response['nic'][0]['ipaddress']
networking['accessConfigs'] = accessconfig
@@ -155,8 +155,7 @@
if virtual_machine_list['listvirtualmachinesresponse']:
response = helper.filter_by_name(
- data=virtual_machine_list[
- 'listvirtualmachinesresponse']['virtualmachine'],
+ data=virtual_machine_list['listvirtualmachinesresponse']['virtualmachine'],
name=instance
)
return response
@@ -282,6 +281,7 @@
function_route = url_for(
'getinstance',
projectid=projectid,
+ zone=zone,
instance=instance)
return errors.resource_not_found(function_route)
diff --git a/gstack/controllers/machine_type.py b/gstack/controllers/machine_type.py
index f2bdd26..f55e211 100755
--- a/gstack/controllers/machine_type.py
+++ b/gstack/controllers/machine_type.py
@@ -126,7 +126,7 @@
authorization=authorization,
args={'keyword': machinetype}
)
- if machinetype_list['listvolumesresponse']:
+ if machinetype_list['listserviceofferingsresponse']:
machinetype = helper.filter_by_name(
data=machinetype_list['listserviceofferingsresponse'][
'serviceoffering'],
diff --git a/gstack/controllers/networks.py b/gstack/controllers/networks.py
index df69812..7fba7ab 100644
--- a/gstack/controllers/networks.py
+++ b/gstack/controllers/networks.py
@@ -49,8 +49,7 @@
if securitygroup_list['listsecuritygroupsresponse']:
response = helper.filter_by_name(
- data=securitygroup_list[
- 'listsecuritygroupsresponse']['securitygroup'],
+ data=securitygroup_list['listsecuritygroupsresponse']['securitygroup'],
name=securitygroup
)
return response
@@ -62,6 +61,7 @@
command = 'createSecurityGroup'
if not args:
args = {}
+
cloudstack_response = requester.make_request(
command,
args,
@@ -123,8 +123,7 @@
return populated_response
-@app.route(
- '/compute/v1/projects/<projectid>/global/networks', methods=['GET'])
+@app.route('/compute/v1/projects/<projectid>/global/networks', methods=['GET'])
@authentication.required
def listnetworks(projectid, authorization):
securitygroup_list = _get_networks(
@@ -185,7 +184,7 @@
'error': {
'errors': [{
'code': 'RESOURCE_ALREADY_EXISTS',
- 'message': 'the resource \'projects/\'' + projectid + '/global/networks/' + args['name']
+ 'message': 'The resource \'projects/\'' + projectid + '/global/networks/' + args['name']
}]
}
}
diff --git a/gstack/controllers/operations.py b/gstack/controllers/operations.py
index e8c1d1e..faa7ad6 100644
--- a/gstack/controllers/operations.py
+++ b/gstack/controllers/operations.py
@@ -51,12 +51,10 @@
}
if async_result['jobstatus'] is 0:
- # handle pending case
populated_response['targetLink'] = ''
populated_response['status'] = 'PENDING'
populated_response['progress'] = 0
elif async_result['jobstatus'] is 1:
- # handle successful case
populated_response['status'] = 'DONE'
populated_response['zone'] = urllib.unquote_plus(
helper.get_root_url() +
@@ -71,9 +69,7 @@
'getinstance',
projectid=projectid,
zone=async_result['jobresult']['virtualmachine']['zonename'],
- instance=async_result['jobresult']['virtualmachine']['displayname']))
-
- # need to add a case here for error handling, its job status 2
+ instance=async_result['jobresult']['virtualmachine']['name']))
return populated_response
diff --git a/gstack/controllers/project.py b/gstack/controllers/project.py
index b18eeba..d6e0776 100755
--- a/gstack/controllers/project.py
+++ b/gstack/controllers/project.py
@@ -156,7 +156,7 @@
return response
-@app.route('//compute/v1/projects/<projectid>', methods=['GET'])
+@app.route('/compute/v1/projects/<projectid>', methods=['GET'])
@authentication.required
def getproject(authorization, projectid):
project = _get_account_by_name(authorization, projectid)
@@ -178,7 +178,7 @@
return res
-@app.route('//compute/v1/projects/<projectid>/setCommonInstanceMetadata', methods=['POST'])
+@app.route('/compute/v1/projects/<projectid>/setCommonInstanceMetadata', methods=['POST'])
@authentication.required
def setglobalmetadata(projectid, authorization):
data = json.loads(request.data)
diff --git a/gstack/controllers/regions.py b/gstack/controllers/regions.py
index a25bdc1..50f3e5d 100755
--- a/gstack/controllers/regions.py
+++ b/gstack/controllers/regions.py
@@ -76,10 +76,12 @@
args={'name': region}
)
- if cloudstack_response['listregionsresponse']:
- cloudstack_response = _cloudstack_region_to_gce(
- cloudstack_response['listregionsresponse']['region'][0])
- return helper.create_response(data=cloudstack_response)
-
- function_route = url_for('getimage', projectid=projectid, image=region)
- return errors.resource_not_found(function_route)
+ if region == cloudstack_response['listregionsresponse']['region'][0]['name']:
+ return helper.create_response(
+ data=_cloudstack_region_to_gce(
+ cloudstack_response['listregionsresponse']['region'][0]
+ )
+ )
+ else:
+ function_route = url_for('getregion', projectid=projectid, region=region)
+ return errors.resource_not_found(function_route)
diff --git a/gstack/controllers/zones.py b/gstack/controllers/zones.py
index 9ff90bd..8e433f3 100755
--- a/gstack/controllers/zones.py
+++ b/gstack/controllers/zones.py
@@ -58,6 +58,8 @@
def get_zone_names(authorization):
zone_list = _get_zones(authorization)
+ print zone_list
+
zones = []
if zone_list['listzonesresponse']:
for zone in zone_list['listzonesresponse']['zone']:
diff --git a/gstack/helpers.py b/gstack/helpers.py
new file mode 100644
index 0000000..d8dddd9
--- /dev/null
+++ b/gstack/helpers.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# 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.
+
+import os
+
+
+def read_file(name):
+ filepath = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ '../',
+ name
+ )
+
+ data = open(filepath)
+ return data.read()
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..9ce950c
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+from unittest import TestCase
+
+import mock
+
+import json
+
+from gstack import app, configure_app
+from gstack.helpers import read_file
+from . import settings
+from .utils import FlaskTestCaseMixin
+
+class GStackTestCase(TestCase):
+ pass
+
+class GStackAppTestCase(FlaskTestCaseMixin, GStackTestCase):
+
+ access_token = ""
+
+ def _configure_app(self):
+ configure_app(settings=settings)
+
+ def _auth_example_user(self):
+ data = {}
+ data['code'] = 'hjrZryvgLYo3R833NkHHV8jYmxQhsD8TjKWzOm2f'
+ data['grant_type'] = 'authorization_code'
+ data['client_id'] = 'ExampleAPIKey'
+ data['client_secret'] = 'eXmaPlEm8XQwezvLOd10Qt3wXH7j9mRgaKbEg3nRDnj7FtlF3yx54EWd9mR5sB1ec5LQDV6gjpy6sfDo6ndUeeww'
+ data['redirect_uri'] = 'http://localhost:8000'
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/list_capabilities.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ self.get('/oauth2/auth?scope=example&redirect_uri=http://127.0.0.1:9999&response_type=code&client_id=ExampleAPIKey&access_type=offline')
+ response = self.post('/oauth2/token', data=data)
+
+ GStackAppTestCase.access_token = json.loads(response.data)['access_token']
+
+ self.assert_ok(response)
+
+
+
+ def setUp(self):
+ super(GStackTestCase, self).setUp()
+ self._configure_app()
+ self.app = app
+ self.client = self.app.test_client()
+ self._auth_example_user()
+ self.app_context = self.app.app_context()
+ self.app_context.push()
+
+ def tearDown(self):
+ super(GStackTestCase, self).tearDown()
+ self.app_context.pop()
+
diff --git a/tests/data/authorize_security_group_ingress.json b/tests/data/authorize_security_group_ingress.json
new file mode 100644
index 0000000..5b20e71
--- /dev/null
+++ b/tests/data/authorize_security_group_ingress.json
@@ -0,0 +1,32 @@
+{ "queryasyncjobresultresponse": {
+ "accountid": "2edb0c28-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "userid": "2edb33ec-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "cmd": "org.apache.cloudstack.api.command.user.securitygroup.AuthorizeSecurityGroupIngressCmd",
+ "jobstatus": 1,
+ "jobprocstatus": 0,
+ "jobresultcode": 0,
+ "jobresulttype": "object",
+ "jobresult": {
+ "securitygroup": {
+ "id": "01104a6a-bd3c-4804-86fd-1ca6231f128d",
+ "name": "test5",
+ "description": "test5",
+ "account": "test",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "domain": "ROOT",
+ "ingressrule": [
+ {
+ "ruleid": "739f53a3-ce50-4790-a86d-1051f77dd3d2",
+ "protocol": "tcp",
+ "startport": 1000,
+ "endport": 1024,
+ "cidr": "0.0.0.0/0"
+ }
+ ],
+ "egressrule": [],
+ "tags": []
+ }
+ },
+ "created": "2014-02-26T23:05:55+0000",
+ "jobid": "ed5d7cc6-776a-4fda-b4c4-b71421b56c82"
+} }
diff --git a/tests/data/create_volume_response.json b/tests/data/create_volume_response.json
new file mode 100644
index 0000000..79826ba
--- /dev/null
+++ b/tests/data/create_volume_response.json
@@ -0,0 +1,38 @@
+{
+ "queryasyncjobresultresponse": {
+ "jobprocstatus": 0,
+ "created": "2014-02-25T19:46:35+0000",
+ "cmd": "org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd",
+ "userid": "2edb33ec-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "jobstatus": 1,
+ "jobid": "1f32404b-d067-43e8-8835-4cc1c55d737a",
+ "jobresultcode": 0,
+ "jobresulttype": "object",
+ "jobresult": {
+ "volume": {
+ "size": 10737418240,
+ "diskofferingname": "Custom",
+ "account": "admin",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "name": "f0e2a699-1196-49bd-90cd-af809f4c32ea",
+ "created": "2014-02-25T19:46:34+0000",
+ "storagetype": "shared",
+ "type": "DATADISK",
+ "tags": [],
+ "domain": "ROOT",
+ "jobstatus": 0,
+ "jobid": "1f32404b-d067-43e8-8835-4cc1c55d737a",
+ "destroyed": false,
+ "state": "Allocated",
+ "diskofferingdisplaytext": "Custom Disk",
+ "isextractable": true,
+ "displayvolume": true,
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "diskofferingid": "46f0a62e-ba3c-4a49-b619-877a8b2a07ed",
+ "id": "8552cdce-879a-42f3-bdb5-2e7f55a38996",
+ "zonename": "Sandbox-simulator"
+ }
+ },
+ "accountid": "2edb0c28-95e4-11e3-b2e4-d19c9d3e5e1d"
+ }
+}
diff --git a/tests/data/delete_keypair.json b/tests/data/delete_keypair.json
new file mode 100644
index 0000000..7c3d5a3
--- /dev/null
+++ b/tests/data/delete_keypair.json
@@ -0,0 +1,3 @@
+{ "deletesshkeypairresponse": {
+ "success": "true"
+} }
diff --git a/tests/data/empty_describe_disk_offerings.json b/tests/data/empty_describe_disk_offerings.json
new file mode 100644
index 0000000..27d411d
--- /dev/null
+++ b/tests/data/empty_describe_disk_offerings.json
@@ -0,0 +1,3 @@
+{
+ "listdiskofferingsresponse": {}
+}
diff --git a/tests/data/empty_describe_images.json b/tests/data/empty_describe_images.json
new file mode 100644
index 0000000..c09958e
--- /dev/null
+++ b/tests/data/empty_describe_images.json
@@ -0,0 +1,5 @@
+{
+ "listtemplatesresponse": {
+ "template": {}
+ }
+}
diff --git a/tests/data/empty_describe_instances.json b/tests/data/empty_describe_instances.json
new file mode 100644
index 0000000..10f969e
--- /dev/null
+++ b/tests/data/empty_describe_instances.json
@@ -0,0 +1,5 @@
+{
+ "listvirtualmachinesresponse": {
+ "virtualmachine": {}
+ }
+}
diff --git a/tests/data/empty_describe_key_pairs.json b/tests/data/empty_describe_key_pairs.json
new file mode 100644
index 0000000..6c70975
--- /dev/null
+++ b/tests/data/empty_describe_key_pairs.json
@@ -0,0 +1,5 @@
+{
+ "listsshkeypairsresponse": {
+ "sshkeypair": {}
+ }
+}
diff --git a/tests/data/empty_describe_security_groups.json b/tests/data/empty_describe_security_groups.json
new file mode 100644
index 0000000..6fbea9f
--- /dev/null
+++ b/tests/data/empty_describe_security_groups.json
@@ -0,0 +1,5 @@
+{
+ "listsecuritygroupsresponse": {
+ "securitygroup": {}
+ }
+}
diff --git a/tests/data/empty_describe_volumes.json b/tests/data/empty_describe_volumes.json
new file mode 100644
index 0000000..2cd5f48
--- /dev/null
+++ b/tests/data/empty_describe_volumes.json
@@ -0,0 +1,5 @@
+{
+ "listvolumesresponse": {
+ "volume": {}
+ }
+}
diff --git a/tests/data/empty_describe_zone.json b/tests/data/empty_describe_zone.json
new file mode 100644
index 0000000..c575b3d
--- /dev/null
+++ b/tests/data/empty_describe_zone.json
@@ -0,0 +1,5 @@
+{
+ "listzonesresponse": {
+ "zone": {}
+ }
+}
diff --git a/tests/data/invalid_image_id.json b/tests/data/invalid_image_id.json
new file mode 100644
index 0000000..0ca8f90
--- /dev/null
+++ b/tests/data/invalid_image_id.json
@@ -0,0 +1,8 @@
+{
+ "listtemplatesresponse": {
+ "errorcode": 431,
+ "uuidlist": [],
+ "cserrorcode": 4350,
+ "errortext": "Please specify a valid template ID."
+ }
+}
diff --git a/tests/data/list_capabilities.json b/tests/data/list_capabilities.json
new file mode 100644
index 0000000..4818292
--- /dev/null
+++ b/tests/data/list_capabilities.json
@@ -0,0 +1,15 @@
+{
+ "listcapabilitiesresponse": {
+ "capability": {
+ "customdiskofferingmaxsize": 1024,
+ "cloudstackversion": "4.3.0",
+ "projectinviterequired": false,
+ "securitygroupsenabled": true,
+ "regionsecondaryenabled": false,
+ "userpublictemplateenabled": false,
+ "supportELB": "false",
+ "allowusercreateprojects": false,
+ "kvmsnapshotenabled": true
+ }
+ }
+}
diff --git a/tests/data/list_zone_by_name_response.json b/tests/data/list_zone_by_name_response.json
new file mode 100644
index 0000000..8fb517c
--- /dev/null
+++ b/tests/data/list_zone_by_name_response.json
@@ -0,0 +1,19 @@
+{
+ "listzonesresponse": {
+ "count": 1,
+ "zone": [
+ {
+ "localstorageenabled": false,
+ "name": "Sandbox-simulator",
+ "zonetoken": "038bf1a4-c55c-3d1e-9176-b42e22ee00c1",
+ "dns1": "8.8.8.8",
+ "securitygroupsenabled": true,
+ "allocationstate": "Enabled",
+ "internaldns1": "8.8.8.8",
+ "dhcpprovider": "VirtualRouter",
+ "networktype": "Basic",
+ "id": "1e47a2fc-61c7-401c-b90e-416b472ada64"
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_create_keypair.json b/tests/data/valid_create_keypair.json
new file mode 100644
index 0000000..f5383fb
--- /dev/null
+++ b/tests/data/valid_create_keypair.json
@@ -0,0 +1,7 @@
+{ "createsshkeypairresponse": {
+ "keypair": {
+ "name": "Test",
+ "fingerprint": "f1:85:d8:d6:54:3c:3e:41:49:52:82:1b:a6:4e:7e:31",
+ "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIICWwIBAAKBgQCLFWb+Y+zxkDMSTmLu7XzOIFccIe6/TWG0BLA53xOPyoRTM4j0\n1cGF2m4VSQ8QLOXztqO22O+zOU5eOtps5kZKk0IHpVGiTeNEfovogVnQx4A3qcC+\nwKHFvjidlT6Cdy8av6erBS18W2NEtkipPEN1Kyirf5EDCz8gMcqRFxvIIQIDAQAB\nAoGAK8Dy4qp62s97UZH5S6LIdWv1G3ONUP898kzbR4lm9QBHuojm1+b692ns4aNX\nKsaFHLNjM11xotcvUTOAjWuvxsDaiE8wAxJI8Zv40QjJ3YO9zbrsbYoysXKJCVLx\nEDB+HWaAb6gRprffuxu50py54RwTyXmhsuuIFcpKn07p32UCQQD42dCvq9p2Qu4Y\nLuVn88kukc7wE3u/phLBaGGxAOEYvXH19rByKgzNYcKeZkrOrqbFEd7YiH/rsJz5\nuY1Jh/OPAkEAjxRMiy5G3SbToC8IOEsLPY0USyOmx1Domd6HEGDOT7OIUoP9gsSr\nuH23C73IzBFstxxhU+MkjZIY2dEY8ULxTwJAbNUl9Y5dTtdatezcm6f81ociT9DV\nkC2bikaSYw0VZPKFgqLO7D8DtlcI/KmUEexEN2/nXB/mgjeNj5Hc/smcdQJATEfK\nNznI1gbpNLFedIStzXb1psmvFPxxxfb5kyXJWHyi5TsxYRJxar67ZCsebo2rpEQh\nL5Qd3MxTK21rGtVRyQJAM4HcYNW/VbH0SrhbtkLoHabjPkb3H0g05THq1ZTohWa0\n1UckpzFX46gc2as+ooHGH0KsA7prUqI9AOmAwc28yw==\n-----END RSA PRIVATE KEY-----\n"
+ }
+} }
diff --git a/tests/data/valid_create_security_group.json b/tests/data/valid_create_security_group.json
new file mode 100644
index 0000000..aea931f
--- /dev/null
+++ b/tests/data/valid_create_security_group.json
@@ -0,0 +1,12 @@
+{
+ "createsecuritygroupresponse": {
+ "securitygroup": {
+ "account": "account",
+ "domainid": "66d69e46-a95b-437b-ac6c-bcaa5331999d",
+ "name": "securitygroupname",
+ "domain": "domain",
+ "id": "9684da98-3f7c-4a0b-b968-3ad143f7650d",
+ "description": "security group description"
+ }
+ }
+}
diff --git a/tests/data/valid_delete_security_group.json b/tests/data/valid_delete_security_group.json
new file mode 100644
index 0000000..8617175
--- /dev/null
+++ b/tests/data/valid_delete_security_group.json
@@ -0,0 +1,5 @@
+{
+ "deletesecuritygroupresponse": {
+ "success": "true"
+ }
+}
diff --git a/tests/data/valid_delete_volume.json b/tests/data/valid_delete_volume.json
new file mode 100644
index 0000000..ff38c40
--- /dev/null
+++ b/tests/data/valid_delete_volume.json
@@ -0,0 +1,5 @@
+{
+ "deletevolumeresponse": {
+ "success": "true"
+ }
+}
\ No newline at end of file
diff --git a/tests/data/valid_describe_image.json b/tests/data/valid_describe_image.json
new file mode 100644
index 0000000..a3ef244
--- /dev/null
+++ b/tests/data/valid_describe_image.json
@@ -0,0 +1,35 @@
+{
+ "listtemplatesresponse": {
+ "count": 1,
+ "template": [
+ {
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "ostypename": "CentOS 5.3 (32-bit)",
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "displaytext": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "ostypeid": "2e678976-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "passwordenabled": false,
+ "id": "a32d70ee-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "size": 2147483648,
+ "isready": true,
+ "format": "VHD",
+ "templatetype": "BUILTIN",
+ "crosszones": true,
+ "zonename": "Sandbox-simulator",
+ "status": "Download Complete",
+ "isdynamicallyscalable": false,
+ "tags": [],
+ "isfeatured": true,
+ "sshkeyenabled": false,
+ "isextractable": false,
+ "account": "system",
+ "name": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "created": "2014-02-15T02:50:13+0000",
+ "hypervisor": "Simulator",
+ "ispublic": true,
+ "checksum": ""
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_images.json b/tests/data/valid_describe_images.json
new file mode 100644
index 0000000..79f78ea
--- /dev/null
+++ b/tests/data/valid_describe_images.json
@@ -0,0 +1,35 @@
+{
+ "listtemplatesresponse": {
+ "count": 1,
+ "template": [
+ {
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "ostypename": "CentOS 5.3 (32-bit)",
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "displaytext": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "ostypeid": "2e678976-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "passwordenabled": false,
+ "id": "a32d70ee-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "size": 2147483648,
+ "isready": true,
+ "format": "VHD",
+ "templatetype": "BUILTIN",
+ "crosszones": true,
+ "zonename": "Sandbox-simulator",
+ "status": "Download Complete",
+ "isdynamicallyscalable": false,
+ "tags": [],
+ "isfeatured": true,
+ "sshkeyenabled": false,
+ "isextractable": false,
+ "account": "system",
+ "name": "imagename",
+ "created": "2014-02-15T02:50:13+0000",
+ "hypervisor": "Simulator",
+ "ispublic": true,
+ "checksum": ""
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_instance.json b/tests/data/valid_describe_instance.json
new file mode 100644
index 0000000..4294fa1
--- /dev/null
+++ b/tests/data/valid_describe_instance.json
@@ -0,0 +1,111 @@
+{
+ "listvirtualmachinesresponse": {
+ "count": 1,
+ "virtualmachine": [
+ {
+ "domain": "brogand93@darrenbrogan.ie",
+ "domainid": "42f2b0d0-3953-485f-984d-b8d67185d358",
+ "haenable": false,
+ "templatename": "Linux CentOS 6.5 64-bit",
+ "securitygroup": [
+ {
+ "egressrule": [],
+ "account": "brogand93@darrenbrogan.ie",
+ "description": "Default Security Group",
+ "tags": [],
+ "ingressrule": [],
+ "id": "6033ff41-53ff-4443-b0bb-f6c5c0191c34",
+ "name": "default"
+ }
+ ],
+ "zoneid": "1128bd56-b4d9-4ac6-a7b9-c715b187ce11",
+ "keypair": "brogand93@darrenbrogan.ie",
+ "cpunumber": 1,
+ "passwordenabled": true,
+ "id": "71f13c6d-1590-4e82-9cdd-22eb9bcad0db",
+ "displayvm": true,
+ "state": "Running",
+ "guestosid": "113038d0-a8cd-4d20-92be-ea313f87c3ac",
+ "memory": 1024,
+ "serviceofferingid": "b6cd1ff5-3a2f-4e9d-a4d1-8988c1191fe8",
+ "zonename": "ch-gva-2",
+ "isdynamicallyscalable": false,
+ "displayname": "foobar",
+ "tags": [
+ {
+ "account": "brogand93@darrenbrogan.ie",
+ "domainid": "42f2b0d0-3953-485f-984d-b8d67185d358",
+ "resourcetype": "UserVm",
+ "resourceid": "71f13c6d-1590-4e82-9cdd-22eb9bcad0db",
+ "domain": "brogand93@darrenbrogan.ie",
+ "value": "root:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDqAuui+xCVPXaFD4cP2MuWnDlktg9vMT/SNzF17UiAzKEbxT/mNayTDAr",
+ "key": "0-sshkey-segment"
+ },
+ {
+ "account": "brogand93@darrenbrogan.ie",
+ "domainid": "42f2b0d0-3953-485f-984d-b8d67185d358",
+ "resourcetype": "UserVm",
+ "resourceid": "71f13c6d-1590-4e82-9cdd-22eb9bcad0db",
+ "domain": "brogand93@darrenbrogan.ie",
+ "value": "DbY/BgGYC5bHuGlb/eE1r4EGpwSXZitGkTI4ThldrSp0Em7psO8AibdpYrFxlOmDFp9wKVD6xbY2HT1ySwvKi+ZwSR5yHcEKq15e",
+ "key": "1-sshkey-segment"
+ },
+ {
+ "account": "brogand93@darrenbrogan.ie",
+ "domainid": "42f2b0d0-3953-485f-984d-b8d67185d358",
+ "resourcetype": "UserVm",
+ "resourceid": "71f13c6d-1590-4e82-9cdd-22eb9bcad0db",
+ "domain": "brogand93@darrenbrogan.ie",
+ "value": "V4eez/3qC1vIcssKmwu5+ZBneZAvWAfxHEKsQU0dsCVvHdn8g7tFXXtg4QCGtE4yzK5v3/+f1AdtIi4hvJoMyi8MV0KSa8e/ravd",
+ "key": "2-sshkey-segment"
+ },
+ {
+ "account": "brogand93@darrenbrogan.ie",
+ "domainid": "42f2b0d0-3953-485f-984d-b8d67185d358",
+ "resourcetype": "UserVm",
+ "resourceid": "71f13c6d-1590-4e82-9cdd-22eb9bcad0db",
+ "domain": "brogand93@darrenbrogan.ie",
+ "value": "Hbgj44PncFBB8O6epVdXPbClZwtkz9D6GEQaOArxk9tX8YEgTFnmsnNuaoZgs7giMj2N7jQe2qXh5R0nsTTuH brogand@microv",
+ "key": "3-sshkey-segment"
+ },
+ {
+ "account": "brogand93@darrenbrogan.ie",
+ "domainid": "42f2b0d0-3953-485f-984d-b8d67185d358",
+ "resourcetype": "UserVm",
+ "resourceid": "71f13c6d-1590-4e82-9cdd-22eb9bcad0db",
+ "domain": "brogand93@darrenbrogan.ie",
+ "value": "ac",
+ "key": "4-sshkey-segment"
+ }
+ ],
+ "nic": [
+ {
+ "networkid": "00304a04-c7ea-4e77-a786-18bc64347bf7",
+ "macaddress": "06:b0:2e:00:01:04",
+ "isolationuri": "ec2://untagged",
+ "networkname": "guestNetworkForBasicZone",
+ "gateway": "185.19.28.1",
+ "traffictype": "Guest",
+ "broadcasturi": "vlan://untagged",
+ "netmask": "255.255.254.0",
+ "type": "Shared",
+ "ipaddress": "185.19.28.199",
+ "id": "2b5cc781-d310-43cf-9d68-66719f43855d",
+ "isdefault": true
+ }
+ ],
+ "cpuspeed": 2198,
+ "templateid": "c34bf3f0-318b-4d77-b0ca-f20585d05d32",
+ "affinitygroup": [],
+ "account": "brogand93@darrenbrogan.ie",
+ "name": "instancename",
+ "created": "2014-06-02T21:11:52+0200",
+ "hypervisor": "KVM",
+ "rootdevicetype": "ROOT",
+ "rootdeviceid": 0,
+ "serviceofferingname": "Tiny",
+ "templatedisplaytext": "Linux CentOS 6.5 64-bit 10GB Disk"
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_instances.json b/tests/data/valid_describe_instances.json
new file mode 100644
index 0000000..998904a
--- /dev/null
+++ b/tests/data/valid_describe_instances.json
@@ -0,0 +1,77 @@
+{
+ "listvirtualmachinesresponse": {
+ "count": 2,
+ "virtualmachine": [
+ {
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "haenable": false,
+ "templatename": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "cpunumber": 1,
+ "passwordenabled": false,
+ "instancename": "i-2-5-QA",
+ "id": "43791f77-26f8-48ca-b557-3a9392f735ae",
+ "networkkbswrite": 21184512,
+ "hostname": "SimulatedAgent.74a0cc00-96c0-4b60-a170-7c749c6e2f10",
+ "displayvm": true,
+ "state": "Running",
+ "guestosid": "2e678976-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "cpuused": "10%",
+ "memory": 512,
+ "serviceofferingid": "739292ce-3e12-4643-8ca1-abfdc2b2eb76",
+ "zonename": "Sandbox-simulator",
+ "isdynamicallyscalable": false,
+ "tags": [],
+ "cpuspeed": 500,
+ "templateid": "a32d70ee-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "affinitygroup": [],
+ "account": "admin",
+ "hostid": "e880bd0f-1597-4cec-b108-c61dd02d78fd",
+ "name": "43791f77-26f8-48ca-b557-3a9392f735ae",
+ "networkkbsread": 42369024,
+ "created": "2014-02-21T17:28:40+0000",
+ "hypervisor": "Simulator",
+ "rootdevicetype": "ROOT",
+ "rootdeviceid": 0,
+ "serviceofferingname": "Small Instance",
+ "templatedisplaytext": "CentOS 5.3(64-bit) no GUI (Simulator)"
+ },
+ {
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "haenable": false,
+ "templatename": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "cpunumber": 1,
+ "passwordenabled": false,
+ "instancename": "i-2-3-QA",
+ "id": "aa10a43e-56db-4a34-88bd-1c2a51c0bc04",
+ "networkkbswrite": 119291904,
+ "hostname": "SimulatedAgent.74a0cc00-96c0-4b60-a170-7c749c6e2f10",
+ "displayvm": true,
+ "state": "Running",
+ "guestosid": "2e678976-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "cpuused": "10%",
+ "memory": 512,
+ "serviceofferingid": "739292ce-3e12-4643-8ca1-abfdc2b2eb76",
+ "zonename": "Sandbox-simulator",
+ "isdynamicallyscalable": false,
+ "tags": [],
+ "cpuspeed": 500,
+ "templateid": "a32d70ee-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "affinitygroup": [],
+ "account": "admin",
+ "hostid": "e880bd0f-1597-4cec-b108-c61dd02d78fd",
+ "name": "aa10a43e-56db-4a34-88bd-1c2a51c0bc04",
+ "networkkbsread": 238583808,
+ "created": "2014-02-15T20:04:05+0000",
+ "hypervisor": "Simulator",
+ "rootdevicetype": "ROOT",
+ "rootdeviceid": 0,
+ "serviceofferingname": "Small Instance",
+ "templatedisplaytext": "CentOS 5.3(64-bit) no GUI (Simulator)"
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_key_pairs.json b/tests/data/valid_describe_key_pairs.json
new file mode 100644
index 0000000..17ad4af
--- /dev/null
+++ b/tests/data/valid_describe_key_pairs.json
@@ -0,0 +1,11 @@
+{
+ "listsshkeypairsresponse": {
+ "count": 1,
+ "sshkeypair": [
+ {
+ "name": "test",
+ "fingerprint": "89:e8:53:79:81:75:ac:ae:c3:95:e0:ee:e0:e7:c0:06"
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_regions.json b/tests/data/valid_describe_regions.json
new file mode 100644
index 0000000..d2c2581
--- /dev/null
+++ b/tests/data/valid_describe_regions.json
@@ -0,0 +1,14 @@
+{
+ "listregionsresponse": {
+ "count": 1,
+ "region": [
+ {
+ "portableipserviceenabled": false,
+ "gslbserviceenabled": true,
+ "endpoint": "http://localhost:8080/client/",
+ "id": 1,
+ "name": "regionname"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/tests/data/valid_describe_security_group.json b/tests/data/valid_describe_security_group.json
new file mode 100644
index 0000000..7e95b07
--- /dev/null
+++ b/tests/data/valid_describe_security_group.json
@@ -0,0 +1,40 @@
+{
+ "listsecuritygroupsresponse": {
+ "count": 1,
+ "securitygroup": [
+ {
+ "egressrule": [],
+ "account": "example-account",
+ "domainid": "66d69e46-a95b-437b-ac6c-bcaa5331999d",
+ "description": "Default Security Group",
+ "tags": [],
+ "domain": "example-account",
+ "ingressrule": [
+ {
+ "protocol": "tcp",
+ "cidr": "0.0.0.0/0",
+ "startport": 22,
+ "endport": 22,
+ "ruleid": "3d92cc70-8c84-4e8a-9989-6efcd7ff7905"
+ },
+ {
+ "protocol": "icmp",
+ "cidr": "0.0.0.0/0",
+ "ruleid": "2ba7dd7b-13b2-49ae-bf8e-26ffadd32c9e",
+ "icmpcode": 0,
+ "icmptype": 0
+ },
+ {
+ "protocol": "tcp",
+ "cidr": "0.0.0.0/0",
+ "startport": 8080,
+ "endport": 8080,
+ "ruleid": "c4562b3c-d1b0-4844-a771-3c3434e1a5d0"
+ }
+ ],
+ "id": "1f95ee9b-b291-48c1-9492-0eee632677e3",
+ "name": "networkname"
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_security_groups.json b/tests/data/valid_describe_security_groups.json
new file mode 100644
index 0000000..a374056
--- /dev/null
+++ b/tests/data/valid_describe_security_groups.json
@@ -0,0 +1,67 @@
+{
+ "listsecuritygroupsresponse": {
+ "count": 3,
+ "securitygroup": [
+ {
+ "egressrule": [],
+ "account": "example-account",
+ "domainid": "66d69e46-a95b-437b-ac6c-bcaa5331999d",
+ "description": "Default Security Group",
+ "tags": [],
+ "domain": "example-account",
+ "ingressrule": [
+ {
+ "protocol": "tcp",
+ "cidr": "0.0.0.0/0",
+ "startport": 22,
+ "endport": 22,
+ "ruleid": "3d92cc70-8c84-4e8a-9989-6efcd7ff7905"
+ },
+ {
+ "protocol": "icmp",
+ "cidr": "0.0.0.0/0",
+ "ruleid": "2ba7dd7b-13b2-49ae-bf8e-26ffadd32c9e",
+ "icmpcode": 0,
+ "icmptype": 0
+ },
+ {
+ "protocol": "tcp",
+ "cidr": "0.0.0.0/0",
+ "startport": 8080,
+ "endport": 8080,
+ "ruleid": "c4562b3c-d1b0-4844-a771-3c3434e1a5d0"
+ }
+ ],
+ "id": "1f95ee9b-b291-48c1-9492-0eee632677e3",
+ "name": "default"
+ },
+ {
+ "egressrule": [],
+ "account": "example-account",
+ "domainid": "66d69e46-a95b-437b-ac6c-bcaa5331999d",
+ "description": "test",
+ "tags": [],
+ "domain": "example-account",
+ "ingressrule": [
+ {
+ "protocol": "tcp",
+ "cidr": "192.168.0.0/24",
+ "startport": 1000,
+ "endport": 1200,
+ "ruleid": "c2e446a1-3778-40cf-a5ff-50ec66a395b6"
+ }
+ ],
+ "id": "7ae5b92f-3a0d-4977-bc33-f1aaecee5776",
+ "name": "test"
+ },
+ {
+ "account": "example-account",
+ "domainid": "66d69e46-a95b-437b-ac6c-bcaa5331999d",
+ "name": "helloworld",
+ "domain": "example-account",
+ "id": "3b637c2e-b0a8-40ae-a7a3-2bef2871d36d",
+ "description": "helloworld"
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_service_offering.json b/tests/data/valid_describe_service_offering.json
new file mode 100644
index 0000000..fd0f1df
--- /dev/null
+++ b/tests/data/valid_describe_service_offering.json
@@ -0,0 +1,23 @@
+{
+ "listserviceofferingsresponse": {
+ "count": 1,
+ "serviceoffering": [
+ {
+ "iscustomized": false,
+ "name": "machinetypename",
+ "created": "2013-02-08T17:20:17+0100",
+ "storagetype": "local",
+ "limitcpuuse": false,
+ "cpuspeed": 2198,
+ "offerha": false,
+ "isvolatile": false,
+ "cpunumber": 1,
+ "memory": 512,
+ "displaytext": "Micro 512mb 1cpu",
+ "issystem": false,
+ "id": "71004023-bb72-4a97-b1e9-bc66dfce9470",
+ "defaultuse": false
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_service_offerings.json b/tests/data/valid_describe_service_offerings.json
new file mode 100644
index 0000000..10237d0
--- /dev/null
+++ b/tests/data/valid_describe_service_offerings.json
@@ -0,0 +1,119 @@
+{
+ "listserviceofferingsresponse": {
+ "count": 7,
+ "serviceoffering": [
+ {
+ "iscustomized": false,
+ "name": "Micro",
+ "created": "2013-02-08T17:20:17+0100",
+ "storagetype": "local",
+ "limitcpuuse": false,
+ "cpuspeed": 2198,
+ "offerha": false,
+ "isvolatile": false,
+ "cpunumber": 1,
+ "memory": 512,
+ "displaytext": "Micro 512mb 1cpu",
+ "issystem": false,
+ "id": "71004023-bb72-4a97-b1e9-bc66dfce9470",
+ "defaultuse": false
+ },
+ {
+ "iscustomized": false,
+ "name": "Tiny",
+ "created": "2013-02-08T17:20:39+0100",
+ "storagetype": "local",
+ "limitcpuuse": false,
+ "cpuspeed": 2198,
+ "offerha": false,
+ "isvolatile": false,
+ "cpunumber": 1,
+ "memory": 1024,
+ "displaytext": "Tiny 1024mb 1cpu",
+ "issystem": false,
+ "id": "b6cd1ff5-3a2f-4e9d-a4d1-8988c1191fe8",
+ "defaultuse": false
+ },
+ {
+ "iscustomized": false,
+ "name": "Small",
+ "created": "2013-02-08T17:21:05+0100",
+ "storagetype": "local",
+ "limitcpuuse": false,
+ "cpuspeed": 2198,
+ "offerha": false,
+ "isvolatile": false,
+ "cpunumber": 2,
+ "memory": 2048,
+ "displaytext": "Small 2048mb 2cpu",
+ "issystem": false,
+ "id": "21624abb-764e-4def-81d7-9fc54b5957fb",
+ "defaultuse": false
+ },
+ {
+ "iscustomized": false,
+ "name": "Medium",
+ "created": "2013-02-08T17:21:43+0100",
+ "storagetype": "local",
+ "limitcpuuse": false,
+ "cpuspeed": 2198,
+ "offerha": false,
+ "isvolatile": false,
+ "cpunumber": 2,
+ "memory": 4096,
+ "displaytext": "Medium 4096mb 2cpu",
+ "issystem": false,
+ "id": "b6e9d1e8-89fc-4db3-aaa4-9b4c5b1d0844",
+ "defaultuse": false
+ },
+ {
+ "iscustomized": false,
+ "name": "Large",
+ "created": "2013-02-08T17:22:27+0100",
+ "storagetype": "local",
+ "limitcpuuse": false,
+ "cpuspeed": 2198,
+ "offerha": false,
+ "isvolatile": false,
+ "cpunumber": 4,
+ "memory": 8182,
+ "displaytext": "Large 8192mb 4cpu",
+ "issystem": false,
+ "id": "c6f99499-7f59-4138-9427-a09db13af2bc",
+ "defaultuse": false
+ },
+ {
+ "iscustomized": false,
+ "name": "Extra-large",
+ "created": "2013-02-08T17:23:38+0100",
+ "storagetype": "local",
+ "limitcpuuse": false,
+ "cpuspeed": 2198,
+ "offerha": false,
+ "isvolatile": false,
+ "cpunumber": 4,
+ "memory": 16384,
+ "displaytext": "Extra-large 16384mb 4cpu",
+ "issystem": false,
+ "id": "350dc5ea-fe6d-42ba-b6c0-efb8b75617ad",
+ "defaultuse": false
+ },
+ {
+ "iscustomized": false,
+ "name": "Huge",
+ "created": "2013-02-08T17:24:10+0100",
+ "storagetype": "local",
+ "limitcpuuse": false,
+ "cpuspeed": 2198,
+ "offerha": false,
+ "isvolatile": false,
+ "cpunumber": 8,
+ "memory": 32184,
+ "displaytext": "Huge 32184mb 8cpu",
+ "issystem": false,
+ "id": "a216b0d1-370f-4e21-a0eb-3dfc6302b564",
+ "defaultuse": false
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_volume.json b/tests/data/valid_describe_volume.json
new file mode 100644
index 0000000..0c96815
--- /dev/null
+++ b/tests/data/valid_describe_volume.json
@@ -0,0 +1,28 @@
+{
+ "listvolumesresponse": {
+ "count": 1,
+ "volume": [
+ {
+ "diskofferingname": "Custom",
+ "account": "admin",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "name": "volumename",
+ "created": "2014-02-22T13:25:12+0000",
+ "storagetype": "shared",
+ "type": "DATADISK",
+ "tags": [],
+ "domain": "ROOT",
+ "isextractable": true,
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "destroyed": false,
+ "state": "Allocated",
+ "diskofferingdisplaytext": "Custom Disk",
+ "displayvolume": true,
+ "size": 10737418240,
+ "diskofferingid": "46f0a62e-ba3c-4a49-b619-877a8b2a07ed",
+ "id": "aa903a80-efa9-4fac-b424-544cbda9fce9",
+ "zonename": "Sandbox-simulator"
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_volumes.json b/tests/data/valid_describe_volumes.json
new file mode 100644
index 0000000..9a95d87
--- /dev/null
+++ b/tests/data/valid_describe_volumes.json
@@ -0,0 +1,55 @@
+{
+ "listvolumesresponse": {
+ "count": 21,
+ "volume": [
+ {
+ "diskofferingname": "Custom",
+ "account": "admin",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "name": "6f78a7d4-8863-40da-96f8-0e10ad4ea94e",
+ "created": "2014-02-22T13:25:12+0000",
+ "storagetype": "shared",
+ "type": "DATADISK",
+ "tags": [],
+ "domain": "ROOT",
+ "isextractable": true,
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "destroyed": false,
+ "state": "Allocated",
+ "diskofferingdisplaytext": "Custom Disk",
+ "displayvolume": true,
+ "size": 10737418240,
+ "diskofferingid": "46f0a62e-ba3c-4a49-b619-877a8b2a07ed",
+ "id": "aa903a80-efa9-4fac-b424-544cbda9fce9",
+ "zonename": "Sandbox-simulator"
+ },
+ {
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "vmname": "43791f77-26f8-48ca-b557-3a9392f735ae",
+ "id": "de2d8297-eaaf-4e81-8ffe-97f37ddbbde5",
+ "size": 5368709120,
+ "diskofferingname": "Small",
+ "diskofferingdisplaytext": "Small Disk, 5 GB",
+ "storage": "PS0",
+ "displayvolume": false,
+ "destroyed": false,
+ "state": "Ready",
+ "type": "DATADISK",
+ "zonename": "Sandbox-simulator",
+ "tags": [],
+ "isextractable": true,
+ "account": "admin",
+ "name": "DATA-5",
+ "virtualmachineid": "43791f77-26f8-48ca-b557-3a9392f735ae",
+ "storagetype": "shared",
+ "hypervisor": "Simulator",
+ "created": "2014-02-21T17:28:41+0000",
+ "deviceid": 1,
+ "diskofferingid": "8fade6f4-13ea-490f-aff2-65c9b37b7651",
+ "vmstate": "Running"
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_describe_zone.json b/tests/data/valid_describe_zone.json
new file mode 100644
index 0000000..4df5d0c
--- /dev/null
+++ b/tests/data/valid_describe_zone.json
@@ -0,0 +1,17 @@
+{
+ "listzonesresponse": {
+ "count": 1,
+ "zone": [
+ {
+ "localstorageenabled": true,
+ "name": "zonename",
+ "zonetoken": "ccb0a60c-79c8-3230-ab8b-8bdbe8c45bb7",
+ "securitygroupsenabled": true,
+ "allocationstate": "Enabled",
+ "dhcpprovider": "VirtualRouter",
+ "networktype": "Basic",
+ "id": "1128bd56-b4d9-4ac6-a7b9-c715b187ce11"
+ }
+ ]
+ }
+}
diff --git a/tests/data/valid_detach_volume.json b/tests/data/valid_detach_volume.json
new file mode 100644
index 0000000..6ad6a0b
--- /dev/null
+++ b/tests/data/valid_detach_volume.json
@@ -0,0 +1,43 @@
+{
+ "queryasyncjobresultresponse": {
+ "jobprocstatus": 0,
+ "created": "2014-03-03T16:57:26+0000",
+ "cmd": "org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd",
+ "userid": "a5fa60a6-a2d5-11e3-8f5e-e2e3ca4a127e",
+ "jobstatus": 1,
+ "jobid": "436927af-f3ed-43ec-96d9-0a63eb97c566",
+ "jobresultcode": 0,
+ "jobresulttype": "object",
+ "jobresult": {
+ "volume": {
+ "domain": "ROOT",
+ "domainid": "a5f9ee28-a2d5-11e3-8f5e-e2e3ca4a127e",
+ "jobstatus": 0,
+ "zoneid": "426baaba-224d-419d-aea1-d65cb21e68ea",
+ "storageid": "Local Storage",
+ "id": "0896ccff-1b7a-4c17-8390-02a602de2efe",
+ "size": 1073741824,
+ "diskofferingname": "Custom",
+ "diskofferingdisplaytext": "Custom Disk",
+ "storage": "devcloud Local Storage",
+ "displayvolume": true,
+ "destroyed": false,
+ "state": "Ready",
+ "type": "DATADISK",
+ "zonename": "devcloud",
+ "tags": [],
+ "isextractable": true,
+ "path": "35e692a8-1135-414f-9c84-9f74e9faa8a4",
+ "account": "admin",
+ "name": "test",
+ "created": "2014-03-03T14:37:47+0000",
+ "storagetype": "local",
+ "hypervisor": "XenServer",
+ "jobid": "436927af-f3ed-43ec-96d9-0a63eb97c566",
+ "diskofferingid": "5ce6263f-ee4b-420c-a921-04570b7bc526",
+ "quiescevm": false
+ }
+ },
+ "accountid": "a5fa2942-a2d5-11e3-8f5e-e2e3ca4a127e"
+ }
+}
diff --git a/tests/data/valid_get_instance_by_id.json b/tests/data/valid_get_instance_by_id.json
new file mode 100644
index 0000000..6d0f023
--- /dev/null
+++ b/tests/data/valid_get_instance_by_id.json
@@ -0,0 +1,58 @@
+{
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "haenable": false,
+ "templatename": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "securitygroup": [
+ {
+ "egressrule": [],
+ "account": "admin",
+ "description": "Default Security Group",
+ "tags": [],
+ "ingressrule": [],
+ "id": "1cc5720a-95e5-11e3-b2e4-d19c9d3e5e1d",
+ "name": "default"
+ }
+ ],
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "cpunumber": 1,
+ "passwordenabled": false,
+ "instancename": "i-2-18-QA",
+ "id": "c3331b5e-b244-4654-8991-a1a019db6168",
+ "displayvm": true,
+ "state": "Stopped",
+ "guestosid": "2e678976-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "cpuspeed": 500,
+ "serviceofferingid": "739292ce-3e12-4643-8ca1-abfdc2b2eb76",
+ "zonename": "Sandbox-simulator",
+ "isdynamicallyscalable": false,
+ "tags": [],
+ "nic": [
+ {
+ "networkid": "344ef1e8-e59e-416b-aa32-9bef9c352903",
+ "macaddress": "06:38:72:00:01:02",
+ "isolationuri": "ec2://untagged",
+ "type": "Shared",
+ "broadcasturi": "vlan://untagged",
+ "traffictype": "Guest",
+ "netmask": "255.255.255.0",
+ "ipaddress": "60.147.41.6",
+ "id": "51226be8-445d-4201-9910-79fc4ff8e837",
+ "networkname": "guestNetworkForBasicZone",
+ "gateway": "60.147.41.1",
+ "isdefault": true
+ }
+ ],
+ "memory": 512,
+ "templateid": "a32d70ee-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "affinitygroup": [],
+ "account": "admin",
+ "name": "c3331b5e-b244-4654-8991-a1a019db6168",
+ "created": "2014-03-03T15:06:55+0000",
+ "hypervisor": "Simulator",
+ "rootdevicetype": "ROOT",
+ "rootdeviceid": 0,
+ "serviceofferingname": "Small Instance",
+ "templatedisplaytext": "CentOS 5.3(64-bit) no GUI (Simulator)"
+}
+
diff --git a/tests/data/valid_import_keypair.json b/tests/data/valid_import_keypair.json
new file mode 100644
index 0000000..6bfcbf9
--- /dev/null
+++ b/tests/data/valid_import_keypair.json
@@ -0,0 +1,6 @@
+{ "registersshkeypairresponse": {
+ "keypair": {
+ "name": "Test22",
+ "fingerprint": "07:69:0e:64:f1:b5:f8:c1:10:25:55:73:1a:5c:39:1d"
+ }
+} }
diff --git a/tests/data/valid_reboot_instance.json b/tests/data/valid_reboot_instance.json
new file mode 100644
index 0000000..6862564
--- /dev/null
+++ b/tests/data/valid_reboot_instance.json
@@ -0,0 +1,79 @@
+{
+ "queryasyncjobresultresponse": {
+ "jobprocstatus": 0,
+ "created": "2014-03-03T15:44:12+0000",
+ "cmd": "org.apache.cloudstack.api.command.user.vm.RebootVMCmd",
+ "userid": "2edb33ec-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "jobstatus": 1,
+ "jobid": "b6b87bc6-47fc-4973-8323-31be506299e5",
+ "jobresultcode": 0,
+ "jobresulttype": "object",
+ "jobresult": {
+ "virtualmachine": {
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "haenable": false,
+ "templatename": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "securitygroup": [
+ {
+ "egressrule": [],
+ "account": "admin",
+ "description": "Default Security Group",
+ "tags": [],
+ "ingressrule": [],
+ "id": "1cc5720a-95e5-11e3-b2e4-d19c9d3e5e1d",
+ "name": "default"
+ }
+ ],
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "cpunumber": 1,
+ "passwordenabled": false,
+ "instancename": "i-2-19-QA",
+ "id": "bc4100f2-e34e-47b0-ba6f-34cfe6d09fec",
+ "networkkbswrite": 344064,
+ "hostname": "SimulatedAgent.74a0cc00-96c0-4b60-a170-7c749c6e2f10",
+ "displayvm": true,
+ "state": "Running",
+ "guestosid": "2e678976-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "cpuused": "10%",
+ "memory": 512,
+ "serviceofferingid": "739292ce-3e12-4643-8ca1-abfdc2b2eb76",
+ "zonename": "Sandbox-simulator",
+ "isdynamicallyscalable": false,
+ "tags": [],
+ "nic": [
+ {
+ "networkid": "344ef1e8-e59e-416b-aa32-9bef9c352903",
+ "macaddress": "06:49:26:00:01:03",
+ "isolationuri": "ec2://untagged",
+ "type": "Shared",
+ "broadcasturi": "vlan://untagged",
+ "traffictype": "Guest",
+ "netmask": "255.255.255.0",
+ "ipaddress": "60.147.41.7",
+ "id": "81b2515b-e6c3-4309-9af8-4eddc376a2c1",
+ "networkname": "guestNetworkForBasicZone",
+ "gateway": "60.147.41.1",
+ "isdefault": true
+ }
+ ],
+ "cpuspeed": 500,
+ "jobstatus": 0,
+ "templateid": "a32d70ee-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "affinitygroup": [],
+ "account": "admin",
+ "hostid": "e880bd0f-1597-4cec-b108-c61dd02d78fd",
+ "name": "bc4100f2-e34e-47b0-ba6f-34cfe6d09fec",
+ "networkkbsread": 688128,
+ "created": "2014-03-03T15:15:45+0000",
+ "hypervisor": "Simulator",
+ "jobid": "b6b87bc6-47fc-4973-8323-31be506299e5",
+ "rootdevicetype": "ROOT",
+ "rootdeviceid": 0,
+ "serviceofferingname": "Small Instance",
+ "templatedisplaytext": "CentOS 5.3(64-bit) no GUI (Simulator)"
+ }
+ },
+ "accountid": "2edb0c28-95e4-11e3-b2e4-d19c9d3e5e1d"
+ }
+}
diff --git a/tests/data/valid_run_instance.json b/tests/data/valid_run_instance.json
new file mode 100644
index 0000000..4eac3f5
--- /dev/null
+++ b/tests/data/valid_run_instance.json
@@ -0,0 +1,76 @@
+{
+ "queryasyncjobresultresponse": {
+ "jobprocstatus": 0,
+ "created": "2014-03-03T21:32:17+0000",
+ "cmd": "org.apache.cloudstack.api.command.user.vm.DeployVMCmd",
+ "userid": "2edb33ec-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "jobstatus": 1,
+ "jobid": "e0b2d780-4d9e-4a4a-8429-fb28f53807dc",
+ "jobresultcode": 0,
+ "jobresulttype": "object",
+ "jobresult": {
+ "virtualmachine": {
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "haenable": false,
+ "templatename": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "jobstatus": 0,
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "cpunumber": 1,
+ "passwordenabled": false,
+ "instancename": "i-2-20-QA",
+ "id": "e8dc9242-ab36-4889-a797-21e22b528fc3",
+ "hostname": "SimulatedAgent.74a0cc00-96c0-4b60-a170-7c749c6e2f10",
+ "displayvm": true,
+ "state": "Running",
+ "guestosid": "2e678976-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "cpuspeed": 500,
+ "serviceofferingid": "739292ce-3e12-4643-8ca1-abfdc2b2eb76",
+ "zonename": "Sandbox-simulator",
+ "isdynamicallyscalable": false,
+ "tags": [],
+ "nic": [
+ {
+ "networkid": "344ef1e8-e59e-416b-aa32-9bef9c352903",
+ "macaddress": "06:4f:98:00:01:03",
+ "isolationuri": "ec2://untagged",
+ "type": "Shared",
+ "broadcasturi": "vlan://untagged",
+ "traffictype": "Guest",
+ "netmask": "255.255.255.0",
+ "ipaddress": "60.147.41.7",
+ "id": "f148a5d7-f43c-4afd-8987-4ebaea370e59",
+ "networkname": "guestNetworkForBasicZone",
+ "gateway": "60.147.41.1",
+ "isdefault": true
+ }
+ ],
+ "memory": 512,
+ "securitygroup": [
+ {
+ "egressrule": [],
+ "account": "admin",
+ "description": "Default Security Group",
+ "tags": [],
+ "ingressrule": [],
+ "id": "1cc5720a-95e5-11e3-b2e4-d19c9d3e5e1d",
+ "name": "default"
+ }
+ ],
+ "templateid": "a32d70ee-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "affinitygroup": [],
+ "account": "admin",
+ "hostid": "e880bd0f-1597-4cec-b108-c61dd02d78fd",
+ "name": "e8dc9242-ab36-4889-a797-21e22b528fc3",
+ "created": "2014-03-03T21:32:17+0000",
+ "hypervisor": "Simulator",
+ "jobid": "e0b2d780-4d9e-4a4a-8429-fb28f53807dc",
+ "rootdevicetype": "ROOT",
+ "rootdeviceid": 0,
+ "serviceofferingname": "Small Instance",
+ "templatedisplaytext": "CentOS 5.3(64-bit) no GUI (Simulator)"
+ }
+ },
+ "accountid": "2edb0c28-95e4-11e3-b2e4-d19c9d3e5e1d"
+ }
+}
diff --git a/tests/data/valid_start_instance.json b/tests/data/valid_start_instance.json
new file mode 100644
index 0000000..697aec3
--- /dev/null
+++ b/tests/data/valid_start_instance.json
@@ -0,0 +1,79 @@
+{
+ "queryasyncjobresultresponse": {
+ "jobprocstatus": 0,
+ "created": "2014-03-03T15:34:40+0000",
+ "cmd": "org.apache.cloudstack.api.command.user.vm.StartVMCmd",
+ "userid": "2edb33ec-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "jobstatus": 1,
+ "jobid": "f2687d7c-e8e2-4dec-8ee9-ce7a1643c93f",
+ "jobresultcode": 0,
+ "jobresulttype": "object",
+ "jobresult": {
+ "virtualmachine": {
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "haenable": false,
+ "templatename": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "securitygroup": [
+ {
+ "egressrule": [],
+ "account": "admin",
+ "description": "Default Security Group",
+ "tags": [],
+ "ingressrule": [],
+ "id": "1cc5720a-95e5-11e3-b2e4-d19c9d3e5e1d",
+ "name": "default"
+ }
+ ],
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "cpunumber": 1,
+ "passwordenabled": false,
+ "instancename": "i-2-19-QA",
+ "id": "bc4100f2-e34e-47b0-ba6f-34cfe6d09fec",
+ "networkkbswrite": 294912,
+ "hostname": "SimulatedAgent.74a0cc00-96c0-4b60-a170-7c749c6e2f10",
+ "displayvm": true,
+ "state": "Running",
+ "guestosid": "2e678976-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "cpuused": "10%",
+ "memory": 512,
+ "serviceofferingid": "739292ce-3e12-4643-8ca1-abfdc2b2eb76",
+ "zonename": "Sandbox-simulator",
+ "isdynamicallyscalable": false,
+ "tags": [],
+ "nic": [
+ {
+ "networkid": "344ef1e8-e59e-416b-aa32-9bef9c352903",
+ "macaddress": "06:49:26:00:01:03",
+ "isolationuri": "ec2://untagged",
+ "type": "Shared",
+ "broadcasturi": "vlan://untagged",
+ "traffictype": "Guest",
+ "netmask": "255.255.255.0",
+ "ipaddress": "60.147.41.7",
+ "id": "81b2515b-e6c3-4309-9af8-4eddc376a2c1",
+ "networkname": "guestNetworkForBasicZone",
+ "gateway": "60.147.41.1",
+ "isdefault": true
+ }
+ ],
+ "cpuspeed": 500,
+ "jobstatus": 0,
+ "templateid": "a32d70ee-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "affinitygroup": [],
+ "account": "admin",
+ "hostid": "e880bd0f-1597-4cec-b108-c61dd02d78fd",
+ "name": "bc4100f2-e34e-47b0-ba6f-34cfe6d09fec",
+ "networkkbsread": 589824,
+ "created": "2014-03-03T15:15:45+0000",
+ "hypervisor": "Simulator",
+ "jobid": "f2687d7c-e8e2-4dec-8ee9-ce7a1643c93f",
+ "rootdevicetype": "ROOT",
+ "rootdeviceid": 0,
+ "serviceofferingname": "Small Instance",
+ "templatedisplaytext": "CentOS 5.3(64-bit) no GUI (Simulator)"
+ }
+ },
+ "accountid": "2edb0c28-95e4-11e3-b2e4-d19c9d3e5e1d"
+ }
+}
diff --git a/tests/data/valid_stop_instance.json b/tests/data/valid_stop_instance.json
new file mode 100644
index 0000000..897e59b
--- /dev/null
+++ b/tests/data/valid_stop_instance.json
@@ -0,0 +1,77 @@
+{
+ "queryasyncjobresultresponse": {
+ "jobprocstatus": 0,
+ "created": "2014-03-03T15:38:21+0000",
+ "cmd": "org.apache.cloudstack.api.command.user.vm.StopVMCmd",
+ "userid": "2edb33ec-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "jobstatus": 1,
+ "jobid": "869b7256-5158-4ed5-b271-2d0f82b1d7f4",
+ "jobresultcode": 0,
+ "jobresulttype": "object",
+ "jobresult": {
+ "virtualmachine": {
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "haenable": false,
+ "templatename": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "securitygroup": [
+ {
+ "egressrule": [],
+ "account": "admin",
+ "description": "Default Security Group",
+ "tags": [],
+ "ingressrule": [],
+ "id": "1cc5720a-95e5-11e3-b2e4-d19c9d3e5e1d",
+ "name": "default"
+ }
+ ],
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "cpunumber": 1,
+ "passwordenabled": false,
+ "instancename": "i-2-19-QA",
+ "id": "bc4100f2-e34e-47b0-ba6f-34cfe6d09fec",
+ "networkkbswrite": 344064,
+ "displayvm": true,
+ "state": "Stopped",
+ "guestosid": "2e678976-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "cpuused": "10%",
+ "cpuspeed": 500,
+ "serviceofferingid": "739292ce-3e12-4643-8ca1-abfdc2b2eb76",
+ "zonename": "Sandbox-simulator",
+ "isdynamicallyscalable": false,
+ "tags": [],
+ "nic": [
+ {
+ "networkid": "344ef1e8-e59e-416b-aa32-9bef9c352903",
+ "macaddress": "06:49:26:00:01:03",
+ "isolationuri": "ec2://untagged",
+ "type": "Shared",
+ "broadcasturi": "vlan://untagged",
+ "traffictype": "Guest",
+ "netmask": "255.255.255.0",
+ "ipaddress": "60.147.41.7",
+ "id": "81b2515b-e6c3-4309-9af8-4eddc376a2c1",
+ "networkname": "guestNetworkForBasicZone",
+ "gateway": "60.147.41.1",
+ "isdefault": true
+ }
+ ],
+ "memory": 512,
+ "jobstatus": 0,
+ "templateid": "a32d70ee-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "affinitygroup": [],
+ "account": "admin",
+ "name": "bc4100f2-e34e-47b0-ba6f-34cfe6d09fec",
+ "networkkbsread": 688128,
+ "created": "2014-03-03T15:15:45+0000",
+ "hypervisor": "Simulator",
+ "jobid": "869b7256-5158-4ed5-b271-2d0f82b1d7f4",
+ "rootdevicetype": "ROOT",
+ "rootdeviceid": 0,
+ "serviceofferingname": "Small Instance",
+ "templatedisplaytext": "CentOS 5.3(64-bit) no GUI (Simulator)"
+ }
+ },
+ "accountid": "2edb0c28-95e4-11e3-b2e4-d19c9d3e5e1d"
+ }
+}
diff --git a/tests/data/valid_terminate_instance.json b/tests/data/valid_terminate_instance.json
new file mode 100644
index 0000000..a435be9
--- /dev/null
+++ b/tests/data/valid_terminate_instance.json
@@ -0,0 +1,77 @@
+{
+ "queryasyncjobresultresponse": {
+ "jobprocstatus": 0,
+ "created": "2014-03-03T15:44:44+0000",
+ "cmd": "org.apache.cloudstack.api.command.user.vm.DestroyVMCmd",
+ "userid": "2edb33ec-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "jobstatus": 1,
+ "jobid": "919ad844-7cd5-4e8a-a60f-8707ef72446c",
+ "jobresultcode": 0,
+ "jobresulttype": "object",
+ "jobresult": {
+ "virtualmachine": {
+ "domain": "ROOT",
+ "domainid": "2edae3e4-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "haenable": false,
+ "templatename": "CentOS 5.3(64-bit) no GUI (Simulator)",
+ "securitygroup": [
+ {
+ "egressrule": [],
+ "account": "admin",
+ "description": "Default Security Group",
+ "tags": [],
+ "ingressrule": [],
+ "id": "1cc5720a-95e5-11e3-b2e4-d19c9d3e5e1d",
+ "name": "default"
+ }
+ ],
+ "zoneid": "1e47a2fc-61c7-401c-b90e-416b472ada64",
+ "cpunumber": 1,
+ "passwordenabled": false,
+ "instancename": "i-2-19-QA",
+ "id": "bc4100f2-e34e-47b0-ba6f-34cfe6d09fec",
+ "networkkbswrite": 360448,
+ "displayvm": true,
+ "state": "Destroyed",
+ "guestosid": "2e678976-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "cpuused": "10%",
+ "cpuspeed": 500,
+ "serviceofferingid": "739292ce-3e12-4643-8ca1-abfdc2b2eb76",
+ "zonename": "Sandbox-simulator",
+ "isdynamicallyscalable": false,
+ "tags": [],
+ "nic": [
+ {
+ "networkid": "344ef1e8-e59e-416b-aa32-9bef9c352903",
+ "macaddress": "06:49:26:00:01:03",
+ "isolationuri": "ec2://untagged",
+ "type": "Shared",
+ "broadcasturi": "vlan://untagged",
+ "traffictype": "Guest",
+ "netmask": "255.255.255.0",
+ "ipaddress": "60.147.41.7",
+ "id": "81b2515b-e6c3-4309-9af8-4eddc376a2c1",
+ "networkname": "guestNetworkForBasicZone",
+ "gateway": "60.147.41.1",
+ "isdefault": true
+ }
+ ],
+ "memory": 512,
+ "jobstatus": 0,
+ "templateid": "a32d70ee-95e4-11e3-b2e4-d19c9d3e5e1d",
+ "affinitygroup": [],
+ "account": "admin",
+ "name": "bc4100f2-e34e-47b0-ba6f-34cfe6d09fec",
+ "networkkbsread": 720896,
+ "created": "2014-03-03T15:15:45+0000",
+ "hypervisor": "Simulator",
+ "jobid": "919ad844-7cd5-4e8a-a60f-8707ef72446c",
+ "rootdevicetype": "ROOT",
+ "rootdeviceid": 0,
+ "serviceofferingname": "Small Instance",
+ "templatedisplaytext": "CentOS 5.3(64-bit) no GUI (Simulator)"
+ }
+ },
+ "accountid": "2edb0c28-95e4-11e3-b2e4-d19c9d3e5e1d"
+ }
+}
diff --git a/tests/data/zones_search.json b/tests/data/zones_search.json
new file mode 100644
index 0000000..c1028d6
--- /dev/null
+++ b/tests/data/zones_search.json
@@ -0,0 +1,12 @@
+{
+ "localstorageenabled": false,
+ "name": "Sandbox-simulator",
+ "zonetoken": "038bf1a4-c55c-3d1e-9176-b42e22ee00c1",
+ "dns1": "8.8.8.8",
+ "securitygroupsenabled": true,
+ "allocationstate": "Enabled",
+ "internaldns1": "8.8.8.8",
+ "dhcpprovider": "VirtualRouter",
+ "networktype": "Basic",
+ "id": "1e47a2fc-61c7-401c-b90e-416b472ada64"
+}
diff --git a/tests/discovery_tests.py b/tests/discovery_tests.py
new file mode 100644
index 0000000..a35724d
--- /dev/null
+++ b/tests/discovery_tests.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+from . import GStackAppTestCase
+
+class DiscoveryTestCase(GStackAppTestCase):
+
+ def test_discovery(self):
+ response = self.get('/discovery/v1/apis/compute/v1/rest')
+
+ self.assert_ok(response)
\ No newline at end of file
diff --git a/tests/disks_tests.py b/tests/disks_tests.py
new file mode 100644
index 0000000..f9635a3
--- /dev/null
+++ b/tests/disks_tests.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import mock
+import json
+
+from gstack.helpers import read_file
+from . import GStackAppTestCase
+
+class DisksTestCase(GStackAppTestCase):
+
+ def test_list_disks(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_volumes.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/examplezone/disks', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_list_disks_with_name_filter(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_volumes.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get(
+ '/compute/v1/projects/projectid/zones/zonename/disks?filter=name+eq+volumename',
+ headers=headers)
+
+ self.assert_ok(response)
+
+ def test_aggregated_list_disks(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_volumes.json')
+ get.return_value.status_code = 200
+
+ get_zones = mock.Mock()
+ get_zones.return_value = json.loads(read_file('tests/data/valid_describe_zone.json'))
+
+ with mock.patch('requests.get', get):
+ with mock.patch(
+ 'gstack.controllers.zones._get_zones',
+ get_zones
+ ):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/projectid/aggregated/disks', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_aggregated_list_disks_with_name_filter(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_volume.json')
+ get.return_value.status_code = 200
+
+ get_zones = mock.Mock()
+ get_zones.return_value = json.loads(read_file('tests/data/valid_describe_zone.json'))
+
+ with mock.patch('requests.get', get):
+ with mock.patch(
+ 'gstack.controllers.zones._get_zones',
+ get_zones
+ ):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get(
+ '/compute/v1/projects/projectid/aggregated/disks?filter=name+eq+volumename',
+ headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_disk(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_volume.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/examplezone/disks/volumename', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_disk_disk_not_found(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/empty_describe_volumes.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/examplezone/disks/volumename', headers=headers)
+
+ self.assert_not_found(response)
+
+ assert 'The resource \'/compute/v1/projects/exampleproject/zones/examplezone/disks/volumename\' was not found' \
+ in response.data
+
diff --git a/tests/firewalls_tests.py b/tests/firewalls_tests.py
new file mode 100644
index 0000000..28f7607
--- /dev/null
+++ b/tests/firewalls_tests.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import mock
+import json
+
+from gstack.helpers import read_file
+from . import GStackAppTestCase
+
+class FirewallsTestCase(GStackAppTestCase):
+
+ def test_list_firewalls(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_security_groups.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/global/firewalls', headers=headers)
+
+ self.assert_ok(response)
+
+
+ def test_get_firewall(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_security_group.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/global/firewalls/securitygroupname', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_firewall_firewall_not_found(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/empty_describe_security_groups.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/global/firewalls/securitygroupname', headers=headers)
+
+ self.assert_not_found(response)
+ assert 'The resource \'/compute/v1/projects/exampleproject/global/firewalls/securitygroupname\' was not found' \
+ in response.data
diff --git a/tests/images_tests.py b/tests/images_tests.py
new file mode 100644
index 0000000..8a9f2c0
--- /dev/null
+++ b/tests/images_tests.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import mock
+
+from gstack.helpers import read_file
+from . import GStackAppTestCase
+
+class ImagesTestCase(GStackAppTestCase):
+
+ def test_list_images(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_images.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/global/images', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_image(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_images.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/global/images/imagename', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_image_image_not_found(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/empty_describe_images.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/global/images/imagename', headers=headers)
+
+ self.assert_not_found(response)
+ assert 'The resource \'/compute/v1/projects/exampleproject/global/images/imagename\' was not found' \
+ in response.data
diff --git a/tests/instances_tests.py b/tests/instances_tests.py
new file mode 100644
index 0000000..47e71c9
--- /dev/null
+++ b/tests/instances_tests.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import mock
+import json
+
+from gstack.helpers import read_file
+from . import GStackAppTestCase
+
+class InstancesTestCase(GStackAppTestCase):
+
+ def test_list_instances(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_instances.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/examplezone/instances', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_aggregated_list_instances(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_instances.json')
+ get.return_value.status_code = 200
+
+ get_zones = mock.Mock()
+ get_zones.return_value = json.loads(read_file('tests/data/valid_describe_zone.json'))
+
+ with mock.patch('requests.get', get):
+ with mock.patch(
+ 'gstack.controllers.zones._get_zones',
+ get_zones
+ ):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/projectid/aggregated/instances', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_list_instances_with_name_filter(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_instance.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get(
+ '/compute/v1/projects/projectid/zones/zonename/instances?filter=name+eq+instancename',
+ headers=headers)
+
+ self.assert_ok(response)
+
+ def test_aggregated_list_instances_with_name_filter(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_instance.json')
+ get.return_value.status_code = 200
+
+ get_zones = mock.Mock()
+ get_zones.return_value = json.loads(read_file('tests/data/valid_describe_zone.json'))
+
+ with mock.patch('requests.get', get):
+ with mock.patch(
+ 'gstack.controllers.zones._get_zones',
+ get_zones
+ ):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get(
+ '/compute/v1/projects/projectid/aggregated/instances?filter=name+eq+instancename',
+ headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_instance(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_instance.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/examplezone/instances/instancename', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_instance_instance_not_found(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/empty_describe_instances.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/examplezone/instances/instancename', headers=headers)
+
+ self.assert_not_found(response)
+ assert 'The resource \'/compute/v1/projects/exampleproject/zones/examplezone/instances/instancename\' was not found' \
+ in response.data
+
+ #def test_delete_instance(self):
+
+ # get = mock.Mock()
+ # get.return_value.text = read_file('tests/data/valid_terminate_instance.json')
+ # get.return_value.status_code = 200
+
+ # get_instance_id = mock.Mock()
+ # get_instance_id.return_value = {'id':'virtualmachineid'}
+
+ # with mock.patch('requests.get', get):
+ # with mock.patch('gstack.controllers.instances._get_virtual_machine_by_name',get_instance_id):
+ # headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ # response = self.delete('/compute/v1/projects/exampleproject/zones/examplezone/instances/instancename', headers=headers)
+
+ # self.assert_ok(response)
+
diff --git a/tests/machine_type_tests.py b/tests/machine_type_tests.py
new file mode 100644
index 0000000..f6e882d
--- /dev/null
+++ b/tests/machine_type_tests.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import mock
+import json
+
+from gstack.helpers import read_file
+from . import GStackAppTestCase
+
+class MachineTypesTestCase(GStackAppTestCase):
+
+ def test_list_machine_types(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_service_offerings.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/examplezone/machineTypes', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_aggregated_list_machine_types(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_service_offerings.json')
+ get.return_value.status_code = 200
+
+ get_zones = mock.Mock()
+ get_zones.return_value = json.loads(read_file('tests/data/valid_describe_zone.json'))
+
+ with mock.patch('requests.get', get):
+ with mock.patch(
+ 'gstack.controllers.zones._get_zones',
+ get_zones
+ ):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/projectid/aggregated/machineTypes', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_list_machine_types_with_name_filter(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_service_offering.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get(
+ '/compute/v1/projects/projectid/zones/zonename/machineTypes?filter=name+eq+machinetypename',
+ headers=headers)
+
+ self.assert_ok(response)
+
+
+ def test_get_machine_type(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_service_offering.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/examplezone/machineTypes/machinetypename', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_machine_type_machine_type_not_found(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_service_offering.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/examplezone/machineTypes/invalidmachinetypename', headers=headers)
+
+ self.assert_not_found(response)
+ assert 'The resource \'/compute/v1/projects/exampleproject/zones/examplezone/machineTypes/invalidmachinetypename\' was not found' \
+ in response.data
+
diff --git a/tests/networks_tests.py b/tests/networks_tests.py
new file mode 100644
index 0000000..2f2f533
--- /dev/null
+++ b/tests/networks_tests.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import mock
+
+from gstack.helpers import read_file
+from . import GStackAppTestCase
+
+class NetworksTestCase(GStackAppTestCase):
+
+ def test_list_networks(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_security_groups.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/global/networks', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_network(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_security_group.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/global/networks/networkname', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_network_network_not_found(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/empty_describe_security_groups.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/global/networks/networkname', headers=headers)
+
+ self.assert_not_found(response)
+ assert 'The resource \'/compute/v1/projects/exampleproject/global/networks/networkname\'' \
+ in response.data
diff --git a/tests/regions_tests.py b/tests/regions_tests.py
new file mode 100644
index 0000000..93f0774
--- /dev/null
+++ b/tests/regions_tests.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import mock
+
+from gstack.helpers import read_file
+from . import GStackAppTestCase
+
+class RegionsTestCase(GStackAppTestCase):
+
+ def test_list_regions(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_regions.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/regions', headers=headers)
+
+ self.assert_ok(response)
+
+
+ def test_get_region(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_regions.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/regions/regionname', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_region_region_not_found(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_regions.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/regions/invalidregionname', headers=headers)
+
+ self.assert_not_found(response)
+ assert 'The resource \'/compute/v1/projects/exampleproject/regions/invalidregionname\' was not found' \
+ in response.data
+
diff --git a/tests/settings.py b/tests/settings.py
new file mode 100644
index 0000000..867bf91
--- /dev/null
+++ b/tests/settings.py
@@ -0,0 +1,11 @@
+PATH = 'compute/v1/projects/'
+GSTACK_BIND_ADDRESS = 'localhost'
+GSTACK_PORT = '5000'
+CLOUDSTACK_HOST = 'api.exoscale.ch'
+CLOUDSTACK_PORT = '443'
+CLOUDSTACK_PROTOCOL = 'https'
+CLOUDSTACK_PATH = '/compute'
+
+DEBUG=False
+
+TESTING = True
diff --git a/tests/utils.py b/tests/utils.py
new file mode 100644
index 0000000..8101ea7
--- /dev/null
+++ b/tests/utils.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+ tests.utils
+ ~~~~~~~~~~~
+
+ test utilities
+"""
+
+
+class FlaskTestCaseMixin(object):
+
+ @staticmethod
+ def _html_data(kwargs):
+ if not kwargs.get('content_type'):
+ kwargs['content_type'] = 'application/x-www-form-urlencoded'
+
+ return kwargs
+
+ @staticmethod
+ def _request(method, *args, **kwargs):
+ return method(*args, **kwargs)
+
+ def post(self, *args, **kwargs):
+ return (
+ self._request(self.client.post, *args, **self._html_data(kwargs))
+ )
+
+ def get(self, *args, **kwargs):
+ return self._request(self.client.get, *args, **kwargs)
+
+ def delete(self, *args, **kwargs):
+ return self._request(self.client.delete, *args, **kwargs)
+
+ def assert_status_code(self, response, status_code):
+ self.assertEquals(status_code, response.status_code)
+ return response
+
+ def assert_ok(self, response):
+ return self.assert_status_code(response, 200)
+
+ def assert_bad_request(self, response):
+ return self.assert_status_code(response, 400)
+
+ def assert_not_found(self, response):
+ return self.assert_status_code(response, 404)
+
diff --git a/tests/zones_tests.py b/tests/zones_tests.py
new file mode 100644
index 0000000..fa89ad8
--- /dev/null
+++ b/tests/zones_tests.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import mock
+
+from gstack.helpers import read_file
+from . import GStackAppTestCase
+
+class ZonesTestCase(GStackAppTestCase):
+
+ def test_list_zones(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_zone.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_zone(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/valid_describe_zone.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/zonename', headers=headers)
+
+ self.assert_ok(response)
+
+ def test_get_zone_zone_not_found(self):
+
+ get = mock.Mock()
+ get.return_value.text = read_file('tests/data/empty_describe_zone.json')
+ get.return_value.status_code = 200
+
+ with mock.patch('requests.get', get):
+ headers = {'authorization': 'Bearer ' + str(GStackAppTestCase.access_token)}
+ response = self.get('/compute/v1/projects/exampleproject/zones/zonename', headers=headers)
+
+ self.assert_not_found(response)
+ assert 'The resource \'/compute/v1/projects/exampleproject/zones/zonename\' was not found' \
+ in response.data