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.')