Merge "Verify Nova create & get Floating IP attributes"
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 6178a1c..e79d23c 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -25,10 +25,10 @@
     _interface = "json"
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(VolumeMultiBackendTest, cls).setUpClass()
         if not CONF.volume_feature_enabled.multi_backend:
-            cls.tearDownClass()
             raise cls.skipException("Cinder multi-backend feature disabled")
 
         cls.backend1_name = CONF.volume.backend1_name
@@ -37,40 +37,36 @@
         cls.volume_client = cls.os_adm.volumes_client
         cls.volume_type_id_list = []
         cls.volume_id_list = []
-        try:
-            # Volume/Type creation (uses backend1_name)
-            type1_name = data_utils.rand_name('Type-')
-            vol1_name = data_utils.rand_name('Volume-')
-            extra_specs1 = {"volume_backend_name": cls.backend1_name}
-            resp, cls.type1 = cls.client.create_volume_type(
-                type1_name, extra_specs=extra_specs1)
-            cls.volume_type_id_list.append(cls.type1['id'])
 
-            resp, cls.volume1 = cls.volume_client.create_volume(
-                size=1, display_name=vol1_name, volume_type=type1_name)
-            cls.volume_id_list.append(cls.volume1['id'])
-            cls.volume_client.wait_for_volume_status(cls.volume1['id'],
+        # Volume/Type creation (uses backend1_name)
+        type1_name = data_utils.rand_name('Type-')
+        vol1_name = data_utils.rand_name('Volume-')
+        extra_specs1 = {"volume_backend_name": cls.backend1_name}
+        resp, cls.type1 = cls.client.create_volume_type(
+            type1_name, extra_specs=extra_specs1)
+        cls.volume_type_id_list.append(cls.type1['id'])
+
+        resp, cls.volume1 = cls.volume_client.create_volume(
+            size=1, display_name=vol1_name, volume_type=type1_name)
+        cls.volume_id_list.append(cls.volume1['id'])
+        cls.volume_client.wait_for_volume_status(cls.volume1['id'],
+                                                 'available')
+
+        if cls.backend1_name != cls.backend2_name:
+            # Volume/Type creation (uses backend2_name)
+            type2_name = data_utils.rand_name('Type-')
+            vol2_name = data_utils.rand_name('Volume-')
+            extra_specs2 = {"volume_backend_name": cls.backend2_name}
+            resp, cls.type2 = cls.client.create_volume_type(
+                type2_name, extra_specs=extra_specs2)
+            cls.volume_type_id_list.append(cls.type2['id'])
+
+            resp, cls.volume2 = cls.volume_client.create_volume(
+                size=1, display_name=vol2_name, volume_type=type2_name)
+            cls.volume_id_list.append(cls.volume2['id'])
+            cls.volume_client.wait_for_volume_status(cls.volume2['id'],
                                                      'available')
 
-            if cls.backend1_name != cls.backend2_name:
-                # Volume/Type creation (uses backend2_name)
-                type2_name = data_utils.rand_name('Type-')
-                vol2_name = data_utils.rand_name('Volume-')
-                extra_specs2 = {"volume_backend_name": cls.backend2_name}
-                resp, cls.type2 = cls.client.create_volume_type(
-                    type2_name, extra_specs=extra_specs2)
-                cls.volume_type_id_list.append(cls.type2['id'])
-
-                resp, cls.volume2 = cls.volume_client.create_volume(
-                    size=1, display_name=vol2_name, volume_type=type2_name)
-                cls.volume_id_list.append(cls.volume2['id'])
-                cls.volume_client.wait_for_volume_status(cls.volume2['id'],
-                                                         'available')
-        except Exception as e:
-            LOG.exception("setup failed: %s" % e)
-            cls.tearDownClass()
-            raise
-
     @classmethod
     def tearDownClass(cls):
         # volumes deletion
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index cd6d7a8..f9fbe18 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -27,6 +27,7 @@
     _interface = "json"
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(VolumesBackupsTest, cls).setUpClass()
 
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index e94c700..0d57d47 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -23,16 +23,13 @@
     _interface = "json"
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(VolumeMetadataTest, cls).setUpClass()
         # Create a volume
         cls.volume = cls.create_volume()
         cls.volume_id = cls.volume['id']
 
-    @classmethod
-    def tearDownClass(cls):
-        super(VolumeMetadataTest, cls).tearDownClass()
-
     def tearDown(self):
         # Update the metadata to {}
         self.volumes_client.update_volume_metadata(self.volume_id, {})
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index c356342..e2f7a38 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -56,6 +56,7 @@
                              [str_vol(v) for v in fetched_list]))
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(VolumesListTest, cls).setUpClass()
         cls.client = cls.volumes_client
@@ -65,24 +66,10 @@
         cls.volume_id_list = []
         cls.metadata = {'Type': 'work'}
         for i in range(3):
-            try:
-                volume = cls.create_volume(metadata=cls.metadata)
-
-                resp, volume = cls.client.get_volume(volume['id'])
-                cls.volume_list.append(volume)
-                cls.volume_id_list.append(volume['id'])
-            except Exception:
-                LOG.exception('Failed to create volume. %d volumes were '
-                              'created' % len(cls.volume_id_list))
-                if cls.volume_list:
-                    # We could not create all the volumes, though we were able
-                    # to create *some* of the volumes. This is typically
-                    # because the backing file size of the volume group is
-                    # too small.
-                    for volid in cls.volume_id_list:
-                        cls.client.delete_volume(volid)
-                        cls.client.wait_for_resource_deletion(volid)
-                raise
+            volume = cls.create_volume(metadata=cls.metadata)
+            resp, volume = cls.client.get_volume(volume['id'])
+            cls.volume_list.append(volume)
+            cls.volume_id_list.append(volume['id'])
 
     @classmethod
     def tearDownClass(cls):
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index 82924a5..a8b0a8d 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -25,6 +25,7 @@
     _interface = 'json'
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(VolumesNegativeTest, cls).setUpClass()
         cls.client = cls.volumes_client
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 84c9501..2ce3a4f 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -24,14 +24,10 @@
     _interface = "json"
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(VolumesSnapshotTest, cls).setUpClass()
-        try:
-            cls.volume_origin = cls.create_volume()
-        except Exception:
-            LOG.exception("setup failed")
-            cls.tearDownClass()
-            raise
+        cls.volume_origin = cls.create_volume()
 
     @classmethod
     def tearDownClass(cls):
diff --git a/tempest/api/volume/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
index 4d2573b..41445d7 100644
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ b/tempest/api/volume/v2/test_volumes_list.py
@@ -56,6 +56,7 @@
                              [str_vol(v) for v in fetched_list]))
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(VolumesV2ListTestJSON, cls).setUpClass()
         cls.client = cls.volumes_client
@@ -65,23 +66,10 @@
         cls.volume_id_list = []
         cls.metadata = {'Type': 'work'}
         for i in range(3):
-            try:
-                volume = cls.create_volume(metadata=cls.metadata)
-                resp, volume = cls.client.get_volume(volume['id'])
-                cls.volume_list.append(volume)
-                cls.volume_id_list.append(volume['id'])
-            except Exception:
-                LOG.exception('Failed to create volume. %d volumes were '
-                              'created' % len(cls.volume_id_list))
-                if cls.volume_list:
-                    # We could not create all the volumes, though we were able
-                    # to create *some* of the volumes. This is typically
-                    # because the backing file size of the volume group is
-                    # too small.
-                    for volid in cls.volume_id_list:
-                        cls.client.delete_volume(volid)
-                        cls.client.wait_for_resource_deletion(volid)
-                raise
+            volume = cls.create_volume(metadata=cls.metadata)
+            resp, volume = cls.client.get_volume(volume['id'])
+            cls.volume_list.append(volume)
+            cls.volume_id_list.append(volume['id'])
 
     @classmethod
     def tearDownClass(cls):
diff --git a/tempest/api_schema/compute/v2/images.py b/tempest/api_schema/compute/v2/images.py
index fb4804d..41b8fff 100644
--- a/tempest/api_schema/compute/v2/images.py
+++ b/tempest/api_schema/compute/v2/images.py
@@ -79,3 +79,38 @@
         'required': ['image']
     }
 }
+
+list_images = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'images': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'id': {'type': 'string'},
+                        'links': {
+                            'type': 'array',
+                            'items': {
+                                'type': 'object',
+                                'properties': {
+                                    'href': {
+                                        'type': 'string',
+                                        'format': 'uri'
+                                    },
+                                    'rel': {'type': 'string'}
+                                },
+                                'required': ['href', 'rel']
+                            }
+                        },
+                        'name': {'type': 'string'}
+                    },
+                    'required': ['id', 'links', 'name']
+                }
+            }
+        },
+        'required': ['images']
+    }
+}
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index deb9c93..2f128f2 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -58,6 +58,7 @@
 
         resp, body = self.get(url)
         body = json.loads(body)
+        self.validate_response(schema.list_images, resp, body)
         return resp, body['images']
 
     def list_images_with_detail(self, params=None):