Merge "Add aggregate json client and tests."
diff --git a/etc/logging.conf.sample b/etc/logging.conf.sample
new file mode 100644
index 0000000..5c1ea5f
--- /dev/null
+++ b/etc/logging.conf.sample
@@ -0,0 +1,30 @@
+[loggers]
+keys=root
+
+[formatters]
+keys=normal,debug
+
+[handlers]
+keys=file,devel
+
+[logger_root]
+level=NOTSET
+handlers=file
+
+[handler_file]
+class=FileHandler
+level=DEBUG
+formatter=normal
+args=('tempest.log', 'w')
+
+[handler_devel]
+class=StreamHandler
+level=DEBUG
+formatter=debug
+args=(sys.stdout,)
+
+[formatter_normal]
+format=%(asctime)s %(levelname)s %(message)s
+
+[formatter_debug]
+format=%(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s
diff --git a/run_tests.sh b/run_tests.sh
index 25b9729..6fcdd90 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -17,6 +17,8 @@
echo " -h, --help Print this usage message"
echo " -d, --debug Debug this script -- set -o xtrace"
echo " -S, --stdout Don't capture stdout"
+ echo " -l, --logging Enable logging"
+ echo " -L, --logging-config Logging config file location. Default is etc/logging.conf"
echo " -- [NOSEOPTIONS] After the first '--' you can pass arbitrary arguments to nosetests "
}
@@ -32,8 +34,10 @@
nova_coverage=0
config_file=""
update=0
+logging=0
+logging_config=etc/logging.conf
-if ! options=$(getopt -o VNnfuswcphdSC: -l virtual-env,no-virtual-env,no-site-packages,force,update,smoke,whitebox,nova-coverage,pep8,help,debug,stdout,config: -- "$@")
+if ! options=$(getopt -o VNnfuswcphdSC:lL: -l virtual-env,no-virtual-env,no-site-packages,force,update,smoke,whitebox,nova-coverage,pep8,help,debug,stdout,config:,logging,logging-config: -- "$@")
then
# parse error
usage
@@ -57,6 +61,8 @@
-s|--smoke) noseargs="$noseargs --attr=type=smoke";;
-w|--whitebox) noseargs="$noseargs --attr=type=whitebox";;
-S|--stdout) noseargs="$noseargs -s";;
+ -l|--logging) logging=1;;
+ -L|--logging-config) logging_config=$2; shift;;
--) [ "yes" == "$first_uu" ] || noseargs="$noseargs $1"; first_uu=no ;;
*) noseargs="$noseargs $1"
esac
@@ -78,6 +84,14 @@
export NOSE_OPENSTACK_SHOW_ELAPSED=1
export NOSE_OPENSTACK_STDOUT=1
+if [ $logging -eq 1 ]; then
+ if [ ! -f "$logging_config" ]; then
+ echo "No such logging config file: $logging_config"
+ exit
+ fi
+ noseargs="$noseargs --logging-config=$logging_config"
+fi
+
if [ $no_site_packages -eq 1 ]; then
installvenvopts="--no-site-packages"
fi
diff --git a/tempest/clients.py b/tempest/clients.py
index 090ff85..642f009 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -79,6 +79,8 @@
InterfacesClientJSON
from tempest.services.compute.xml.interfaces_client import \
InterfacesClientXML
+from tempest.services.compute.json.fixed_ips_client import FixedIPsClientJSON
+from tempest.services.compute.xml.fixed_ips_client import FixedIPsClientXML
LOG = logging.getLogger(__name__)
@@ -167,6 +169,11 @@
"xml": EndPointClientXML,
}
+FIXED_IPS_CLIENT = {
+ "json": FixedIPsClientJSON,
+ "xml": FixedIPsClientXML
+}
+
class Manager(object):
@@ -230,6 +237,7 @@
SECURITY_GROUPS_CLIENT[interface](*client_args)
self.interfaces_client = INTERFACES_CLIENT[interface](*client_args)
self.endpoints_client = ENDPOINT_CLIENT[interface](*client_args)
+ self.fixed_ips_client = FIXED_IPS_CLIENT[interface](*client_args)
except KeyError:
msg = "Unsupported interface type `%s'" % interface
raise exceptions.InvalidConfiguration(msg)
diff --git a/tempest/services/compute/json/fixed_ips_client.py b/tempest/services/compute/json/fixed_ips_client.py
new file mode 100644
index 0000000..4ef7c4c
--- /dev/null
+++ b/tempest/services/compute/json/fixed_ips_client.py
@@ -0,0 +1,40 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp
+# All Rights Reserved.
+#
+# Licensed 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 json
+
+from tempest.common.rest_client import RestClient
+
+
+class FixedIPsClientJSON(RestClient):
+
+ def __init__(self, config, username, password, auth_url, tenant_name=None):
+ super(FixedIPsClientJSON, self).__init__(config, username, password,
+ auth_url, tenant_name)
+ self.service = self.config.compute.catalog_type
+
+ def get_fixed_ip_details(self, fixed_ip):
+ url = "os-fixed-ips/%s" % (fixed_ip)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ return resp, body['fixed_ip']
+
+ def reserve_fixed_ip(self, ip, body):
+ """This reserves and unreserves fixed ips."""
+ url = "os-fixed-ips/%s/action" % (ip)
+ resp, body = self.post(url, json.dumps(body), self.headers)
+ return resp, body
diff --git a/tempest/services/compute/json/interfaces_client.py b/tempest/services/compute/json/interfaces_client.py
index 468a5c2..06e6476 100644
--- a/tempest/services/compute/json/interfaces_client.py
+++ b/tempest/services/compute/json/interfaces_client.py
@@ -14,8 +14,10 @@
# under the License.
import json
+import time
from tempest.common.rest_client import RestClient
+from tempest import exceptions
class InterfacesClientJSON(RestClient):
@@ -55,3 +57,24 @@
resp, body = self.delete('servers/%s/os-interface/%s' % (server,
port_id))
return resp, body
+
+ def wait_for_interface_status(self, server, port_id, status):
+ """Waits for a interface to reach a given status."""
+ resp, body = self.show_interface(server, port_id)
+ interface_status = body['port_state']
+ start = int(time.time())
+
+ while(interface_status != status):
+ time.sleep(self.build_interval)
+ resp, body = self.show_interface(server, port_id)
+ interface_status = body['port_state']
+
+ timed_out = int(time.time()) - start >= self.build_timeout
+
+ if interface_status != status and timed_out:
+ message = ('Interface %s failed to reach %s status within '
+ 'the required time (%s s).' %
+ (port_id, status, self.build_timeout))
+ raise exceptions.TimeoutException(message)
+
+ return resp, body
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 37d4131..5b1e48f 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -35,6 +35,14 @@
body = json.loads(body)
return resp, body['quota_set']
+ def get_default_quota_set(self, tenant_id):
+ """List the default quota set for a tenant."""
+
+ url = 'os-quota-sets/%s/defaults' % str(tenant_id)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ return resp, body['quota_set']
+
def update_quota_set(self, tenant_id, injected_file_content_bytes=None,
metadata_items=None, ram=None, floating_ips=None,
fixed_ips=None, key_pairs=None, instances=None,
diff --git a/tempest/services/compute/xml/fixed_ips_client.py b/tempest/services/compute/xml/fixed_ips_client.py
new file mode 100644
index 0000000..ef023f0
--- /dev/null
+++ b/tempest/services/compute/xml/fixed_ips_client.py
@@ -0,0 +1,54 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp
+# All Rights Reserved.
+#
+# Licensed 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.
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import Document
+from tempest.services.compute.xml.common import Element
+from tempest.services.compute.xml.common import Text
+from tempest.services.compute.xml.common import xml_to_json
+
+
+class FixedIPsClientXML(RestClientXML):
+
+ def __init__(self, config, username, password, auth_url, tenant_name=None):
+ super(FixedIPsClientXML, self).__init__(config, username, password,
+ auth_url, tenant_name)
+ self.service = self.config.compute.catalog_type
+
+ def _parse_fixed_ip_details(self, body):
+ body = xml_to_json(etree.fromstring(body))
+ return body
+
+ def get_fixed_ip_details(self, fixed_ip):
+ url = "os-fixed-ips/%s" % (fixed_ip)
+ resp, body = self.get(url, self.headers)
+ body = self._parse_resp(body)
+ return resp, body
+
+ def reserve_fixed_ip(self, ip, body):
+ """This reserves and unreserves fixed ips."""
+ url = "os-fixed-ips/%s/action" % (ip)
+ # NOTE(maurosr): First converts the dict body to a json string then
+ # accept any action key value here to permit tests to cover cases with
+ # invalid actions raising badrequest.
+ key, value = body.popitem()
+ xml_body = Element(key)
+ xml_body.append(Text(value))
+ resp, body = self.post(url, str(Document(xml_body)), self.headers)
+ return resp, body
diff --git a/tempest/services/compute/xml/interfaces_client.py b/tempest/services/compute/xml/interfaces_client.py
index 4a692a1..a84e0bd 100644
--- a/tempest/services/compute/xml/interfaces_client.py
+++ b/tempest/services/compute/xml/interfaces_client.py
@@ -13,9 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+import time
+
from lxml import etree
from tempest.common.rest_client import RestClientXML
+from tempest import exceptions
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
from tempest.services.compute.xml.common import Text
@@ -80,3 +83,23 @@
resp, body = self.delete('servers/%s/os-interface/%s' % (server,
port_id))
return resp, body
+
+ def wait_for_interface_status(self, server, port_id, status):
+ """Waits for a interface to reach a given status."""
+ resp, body = self.show_interface(server, port_id)
+ interface_status = body['port_state']
+ start = int(time.time())
+
+ while(interface_status != status):
+ time.sleep(self.build_interval)
+ resp, body = self.show_interface(server, port_id)
+ interface_status = body['port_state']
+
+ timed_out = int(time.time()) - start >= self.build_timeout
+
+ if interface_status != status and timed_out:
+ message = ('Interface %s failed to reach %s status within '
+ 'the required time (%s s).' %
+ (port_id, status, self.build_timeout))
+ raise exceptions.TimeoutException(message)
+ return resp, body
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
index 20e04b4..8912443 100644
--- a/tempest/services/compute/xml/quotas_client.py
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -55,6 +55,15 @@
body = self._format_quota(body)
return resp, body
+ def get_default_quota_set(self, tenant_id):
+ """List the default quota set for a tenant."""
+
+ url = 'os-quota-sets/%s/defaults' % str(tenant_id)
+ resp, body = self.get(url, self.headers)
+ body = xml_to_json(etree.fromstring(body))
+ body = self._format_quota(body)
+ return resp, body
+
def update_quota_set(self, tenant_id, injected_file_content_bytes=None,
metadata_items=None, ram=None, floating_ips=None,
fixed_ips=None, key_pairs=None, instances=None,
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index f5fd4a6..331d560 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -42,6 +42,13 @@
version = ip.get('version')
if version:
ip['version'] = int(version)
+ # NOTE(maurosr): just a fast way to avoid the xml version with the
+ # expanded xml namespace.
+ type_ns_prefix = ('{http://docs.openstack.org/compute/ext/extended_ips/'
+ 'api/v1.1}type')
+ if type_ns_prefix in ip:
+ ip['OS-EXT-IPS:type'] = ip[type_ns_prefix]
+ ip.pop(type_ns_prefix)
return ip
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index a3b3e96..a8fab7f 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -139,7 +139,8 @@
headers = {}
- for option in ['is_public', 'location', 'properties', 'copy_from']:
+ for option in ['is_public', 'location', 'properties',
+ 'copy_from', 'min_ram']:
if option in kwargs:
params[option] = kwargs.get(option)
diff --git a/tempest/tests/compute/admin/test_fixed_ips.py b/tempest/tests/compute/admin/test_fixed_ips.py
new file mode 100644
index 0000000..d8b1359
--- /dev/null
+++ b/tempest/tests/compute/admin/test_fixed_ips.py
@@ -0,0 +1,108 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp
+# All Rights Reserved.
+#
+# Licensed 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.
+
+from tempest import exceptions
+from tempest.test import attr
+from tempest.tests.compute import base
+
+
+class FixedIPsBase(base.BaseComputeAdminTest):
+ _interface = 'json'
+ ip = None
+
+ @classmethod
+ def setUpClass(cls):
+ super(FixedIPsBase, cls).setUpClass()
+ # NOTE(maurosr): The idea here is: the server creation is just an
+ # auxiliary element to the ip details or reservation, there was no way
+ # (at least none in my mind) to get an valid and existing ip except
+ # by creating a server and using its ip. So the intention is to create
+ # fewer server possible (one) and use it to both: json and xml tests.
+ # This decreased time to run both tests, in my test machine, from 53
+ # secs to 29 (agains 23 secs when running only json tests)
+ if cls.ip is None:
+ cls.client = cls.os_adm.fixed_ips_client
+ cls.non_admin_client = cls.fixed_ips_client
+ resp, server = cls.create_server(wait_until='ACTIVE')
+ resp, server = cls.servers_client.get_server(server['id'])
+ for ip_set in server['addresses']:
+ for ip in server['addresses'][ip_set]:
+ if ip['OS-EXT-IPS:type'] == 'fixed':
+ cls.ip = ip['addr']
+ break
+ if cls.ip:
+ break
+
+
+class FixedIPsTestJson(FixedIPsBase):
+ _interface = 'json'
+
+ @attr(type='positive')
+ def test_list_fixed_ip_details(self):
+ resp, fixed_ip = self.client.get_fixed_ip_details(self.ip)
+ self.assertEqual(fixed_ip['address'], self.ip)
+
+ @attr(type='negative')
+ def test_list_fixed_ip_details_with_non_admin_user(self):
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.get_fixed_ip_details, self.ip)
+
+ @attr(type='positive')
+ def test_set_reserve(self):
+ body = {"reserve": "None"}
+ resp, body = self.client.reserve_fixed_ip(self.ip, body)
+ self.assertEqual(resp.status, 202)
+
+ @attr(type='positive')
+ def test_set_unreserve(self):
+ body = {"unreserve": "None"}
+ resp, body = self.client.reserve_fixed_ip(self.ip, body)
+ self.assertEqual(resp.status, 202)
+
+ @attr(type='negative')
+ def test_set_reserve_with_non_admin_user(self):
+ body = {"reserve": "None"}
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.reserve_fixed_ip,
+ self.ip, body)
+
+ @attr(type='negative')
+ def test_set_unreserve_with_non_admin_user(self):
+ body = {"unreserve": "None"}
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.reserve_fixed_ip,
+ self.ip, body)
+
+ @attr(type='negative')
+ def test_set_reserve_with_invalid_ip(self):
+ # NOTE(maurosr): since this exercises the same code snippet, we do it
+ # only for reserve action
+ body = {"reserve": "None"}
+ self.assertRaises(exceptions.NotFound,
+ self.client.reserve_fixed_ip,
+ "my.invalid.ip", body)
+
+ @attr(type='negative')
+ def test_fixed_ip_with_invalid_action(self):
+ body = {"invalid_action": "None"}
+ self.assertRaises(exceptions.BadRequest,
+ self.client.reserve_fixed_ip,
+ self.ip, body)
+
+
+class FixedIPsTestXml(FixedIPsTestJson):
+ _interface = 'xml'
diff --git a/tempest/tests/compute/admin/test_quotas.py b/tempest/tests/compute/admin/test_quotas.py
index 5a9b6f9..8f520f9 100644
--- a/tempest/tests/compute/admin/test_quotas.py
+++ b/tempest/tests/compute/admin/test_quotas.py
@@ -63,12 +63,10 @@
# Admin can get the default resource quota set for a tenant
expected_quota_set = self.default_quota_set.copy()
expected_quota_set['id'] = self.demo_tenant_id
- try:
- resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
- self.assertEqual(200, resp.status)
- self.assertEqual(expected_quota_set, quota_set)
- except Exception:
- self.fail("Admin could not get the default quota set for a tenant")
+ resp, quota_set = self.client.get_default_quota_set(
+ self.demo_tenant_id)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(expected_quota_set, quota_set)
def test_update_all_quota_resources_for_tenant(self):
# Admin can update all the resource quota limits for a tenant
diff --git a/tempest/tests/compute/base.py b/tempest/tests/compute/base.py
index 87aa889..7716922 100644
--- a/tempest/tests/compute/base.py
+++ b/tempest/tests/compute/base.py
@@ -60,6 +60,7 @@
cls.volumes_extensions_client = os.volumes_extensions_client
cls.volumes_client = os.volumes_client
cls.interfaces_client = os.interfaces_client
+ cls.fixed_ips_client = os.fixed_ips_client
cls.build_interval = cls.config.compute.build_interval
cls.build_timeout = cls.config.compute.build_timeout
cls.ssh_user = cls.config.compute.ssh_user
diff --git a/tempest/tests/compute/servers/test_attach_interfaces.py b/tempest/tests/compute/servers/test_attach_interfaces.py
index 47c0575..5e447c4 100644
--- a/tempest/tests/compute/servers/test_attach_interfaces.py
+++ b/tempest/tests/compute/servers/test_attach_interfaces.py
@@ -25,7 +25,7 @@
@classmethod
def setUpClass(cls):
super(AttachInterfacesTestJSON, cls).setUpClass()
- os = clients.Manager()
+ os = clients.Manager(interface=cls._interface)
if not os.config.network.quantum_available:
raise cls.skipException("Quantum is required")
cls.client = os.interfaces_client
@@ -41,13 +41,18 @@
self.assertEqual(iface['fixed_ips'][0]['ip_address'], fixed_ip)
def _create_server_get_interfaces(self):
- server = self.create_server()
+ resp, server = self.create_server()
self.os.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
resp, ifs = self.client.list_interfaces(server['id'])
+ resp, body = self.client.wait_for_interface_status(
+ server['id'], ifs[0]['port_id'], 'ACTIVE')
+ ifs[0]['port_state'] = body['port_state']
return server, ifs
def _test_create_interface(self, server):
resp, iface = self.client.create_interface(server['id'])
+ resp, iface = self.client.wait_for_interface_status(
+ server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface)
return iface
@@ -55,6 +60,8 @@
network_id = ifs[0]['net_id']
resp, iface = self.client.create_interface(server['id'],
network_id=network_id)
+ resp, iface = self.client.wait_for_interface_status(
+ server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface, network_id=network_id)
return iface
diff --git a/tempest/tests/compute/test_quotas.py b/tempest/tests/compute/test_quotas.py
index a84d041..92e5a70 100644
--- a/tempest/tests/compute/test_quotas.py
+++ b/tempest/tests/compute/test_quotas.py
@@ -30,23 +30,31 @@
resp, tenants = cls.admin_client.list_tenants()
cls.tenant_id = [tnt['id'] for tnt in tenants if tnt['name'] ==
cls.client.tenant_name][0]
+ cls.default_quota_set = {'injected_file_content_bytes': 10240,
+ 'metadata_items': 128, 'injected_files': 5,
+ 'ram': 51200, 'floating_ips': 10,
+ 'fixed_ips': -1, 'key_pairs': 100,
+ 'injected_file_path_bytes': 255,
+ 'instances': 10, 'security_group_rules': 20,
+ 'cores': 20, 'security_groups': 10}
+
+ @attr(type='smoke')
+ def test_get_quotas(self):
+ # User can get the quota set for it's tenant
+ expected_quota_set = self.default_quota_set.copy()
+ expected_quota_set['id'] = self.tenant_id
+ resp, quota_set = self.client.get_quota_set(self.tenant_id)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(expected_quota_set, quota_set)
@attr(type='smoke')
def test_get_default_quotas(self):
# User can get the default quota set for it's tenant
- expected_quota_set = {'injected_file_content_bytes': 10240,
- 'metadata_items': 128, 'injected_files': 5,
- 'ram': 51200, 'floating_ips': 10,
- 'fixed_ips': -1, 'key_pairs': 100,
- 'injected_file_path_bytes': 255, 'instances': 10,
- 'security_group_rules': 20, 'cores': 20,
- 'id': self.tenant_id, 'security_groups': 10}
- try:
- resp, quota_set = self.client.get_quota_set(self.tenant_id)
- self.assertEqual(200, resp.status)
- self.assertEqual(expected_quota_set, quota_set)
- except Exception:
- self.fail("Quota set for tenant did not have default limits")
+ expected_quota_set = self.default_quota_set.copy()
+ expected_quota_set['id'] = self.tenant_id
+ resp, quota_set = self.client.get_default_quota_set(self.tenant_id)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(expected_quota_set, quota_set)
class QuotasTestXML(QuotasTestJSON):
diff --git a/tempest/tests/image/v1/test_images.py b/tempest/tests/image/v1/test_images.py
index 1b6fa10..0065d27 100644
--- a/tempest/tests/image/v1/test_images.py
+++ b/tempest/tests/image/v1/test_images.py
@@ -117,6 +117,26 @@
self.assertEqual(resp['status'], '200')
self.assertEqual(body, data)
+ @attr(type='image')
+ def test_register_image_with_min_ram(self):
+ # Register an image with min ram
+ properties = {'prop1': 'val1'}
+ resp, body = self.create_image(name='New_image_with_min_ram',
+ container_format='bare',
+ disk_format='raw',
+ is_public=True,
+ min_ram=40,
+ properties=properties)
+ self.assertTrue('id' in body)
+ image_id = body.get('id')
+ self.created_images.append(image_id)
+ self.assertEqual('New_image_with_min_ram', body.get('name'))
+ self.assertTrue(body.get('is_public'))
+ self.assertEqual('queued', body.get('status'))
+ self.assertEqual(40, body.get('min_ram'))
+ for key, val in properties.items():
+ self.assertEqual(val, body.get('properties')[key])
+
class ListImagesTest(base.BaseV1ImageTest):
diff --git a/tempest/tests/network/test_network_basic_ops.py b/tempest/tests/network/test_network_basic_ops.py
index 3afe8e3..92ca65f 100644
--- a/tempest/tests/network/test_network_basic_ops.py
+++ b/tempest/tests/network/test_network_basic_ops.py
@@ -17,6 +17,7 @@
# under the License.
from tempest.common.utils.data_utils import rand_name
+from tempest.test import attr
import tempest.tests.network.common as net_common
@@ -148,14 +149,17 @@
self.set_resource(name, router)
return router
+ @attr(type='smoke')
def test_001_create_keypairs(self):
self.keypairs[self.tenant_id] = self._create_keypair(
self.compute_client)
+ @attr(type='smoke')
def test_002_create_security_groups(self):
self.security_groups[self.tenant_id] = self._create_security_group(
self.compute_client)
+ @attr(type='smoke')
def test_003_create_networks(self):
network = self._create_network(self.tenant_id)
router = self._get_router(self.tenant_id)
@@ -165,6 +169,7 @@
self.subnets.append(subnet)
self.routers.append(router)
+ @attr(type='smoke')
def test_004_check_networks(self):
#Checks that we see the newly created network/subnet/router via
#checking the result of list_[networks,routers,subnets]
@@ -188,6 +193,7 @@
self.assertIn(myrouter.name, seen_router_names)
self.assertIn(myrouter.id, seen_router_ids)
+ @attr(type='smoke')
def test_005_create_servers(self):
if not (self.keypairs or self.security_groups or self.networks):
raise self.skipTest('Necessary resources have not been defined')
@@ -200,6 +206,7 @@
name, keypair_name, security_groups)
self.servers.append(server)
+ @attr(type='smoke')
def test_006_check_tenant_network_connectivity(self):
if not self.config.network.tenant_networks_reachable:
msg = 'Tenant networks not configured to be reachable.'
@@ -213,6 +220,7 @@
"Timed out waiting for %s's ip to become "
"reachable" % server.name)
+ @attr(type='smoke')
def test_007_assign_floating_ips(self):
public_network_id = self.config.network.public_network_id
if not public_network_id:
@@ -224,6 +232,7 @@
self.floating_ips.setdefault(server, [])
self.floating_ips[server].append(floating_ip)
+ @attr(type='smoke')
def test_008_check_public_network_connectivity(self):
if not self.floating_ips:
raise self.skipTest('No floating ips have been allocated.')