Merge "Make every swift clients use expected_success"
diff --git a/HACKING.rst b/HACKING.rst
index 8fbc9bb..e57b670 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -213,8 +213,10 @@
 Sample Configuration File
 -------------------------
 The sample config file is autogenerated using a script. If any changes are made
-to the config variables in tempest then the sample config file must be
-regenerated. This can be done running the script: tools/generate_sample.sh
+to the config variables in tempest/config.py then the sample config file must be
+regenerated. This can be done running::
+
+  tox -egenconfig
 
 Unit Tests
 ----------
diff --git a/tempest/api/compute/admin/test_flavors_negative.py b/tempest/api/compute/admin/test_flavors_negative.py
index 3389aee..5bc3d10 100644
--- a/tempest/api/compute/admin/test_flavors_negative.py
+++ b/tempest/api/compute/admin/test_flavors_negative.py
@@ -58,7 +58,7 @@
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  self.ram,
                                                  self.vcpus, self.disk,
-                                                 '',
+                                                 None,
                                                  ephemeral=self.ephemeral,
                                                  swap=self.swap,
                                                  rxtx=self.rxtx)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index dd81a09..b9086cc 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -12,6 +12,7 @@
 #    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 itertools
 
 import netaddr
 import testtools
@@ -42,6 +43,7 @@
         network update
         subnet update
         delete a network also deletes its subnets
+        list external networks
 
         All subnet tests are run once with ipv4 and once with ipv6.
 
@@ -345,6 +347,28 @@
             enable_dhcp=True,
             **self.subnet_dict(['gateway', 'host_routes', 'dns_nameservers']))
 
+    @test.attr(type='smoke')
+    def test_external_network_visibility(self):
+        """Verifies user can see external networks but not subnets."""
+        _, body = self.client.list_networks(**{'router:external': True})
+        networks = [network['id'] for network in body['networks']]
+        self.assertNotEmpty(networks, "No external networks found")
+
+        nonexternal = [net for net in body['networks'] if
+                       not net['router:external']]
+        self.assertEmpty(nonexternal, "Found non-external networks"
+                                      " in filtered list (%s)." % nonexternal)
+        self.assertIn(CONF.network.public_network_id, networks)
+
+        subnets_iter = (network['subnets'] for network in body['networks'])
+        # subnets_iter is a list (iterator) of lists. This flattens it to a
+        # list of UUIDs
+        public_subnets_iter = itertools.chain(*subnets_iter)
+        _, body = self.client.list_subnets()
+        subnets = [sub['id'] for sub in body['subnets']
+                   if sub['id'] in public_subnets_iter]
+        self.assertEmpty(subnets, "Public subnets visible")
+
 
 class NetworksTestXML(NetworksTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 8c2fdeb..fe06fd0 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -140,10 +140,9 @@
     def test_delete_container(self):
         # create a container
         container_name = self._create_container()
-        # delete container
+        # delete container, success asserted within
         resp, _ = self.container_client.delete_container(container_name)
         self.assertHeaders(resp, 'Container', 'DELETE')
-
         self.containers.remove(container_name)
 
     @test.attr(type='smoke')
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index a0792f1..a481224 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -21,7 +21,7 @@
 CONF = config.CONF
 
 
-class VolumeTypesTest(base.BaseVolumeV1AdminTest):
+class VolumeTypesV2Test(base.BaseVolumeAdminTest):
     _interface = "json"
 
     def _delete_volume(self, volume_id):
@@ -43,6 +43,7 @@
         volume = {}
         vol_name = data_utils.rand_name("volume-")
         vol_type_name = data_utils.rand_name("volume-type-")
+        self.name_field = self.special_fields['name_field']
         proto = CONF.volume.storage_protocol
         vendor = CONF.volume.vendor_name
         extra_specs = {"storage_protocol": proto,
@@ -54,21 +55,20 @@
         self.assertIn('id', body)
         self.addCleanup(self._delete_volume_type, body['id'])
         self.assertIn('name', body)
+        params = {self.name_field: vol_name, 'volume_type': vol_type_name}
         _, volume = self.volumes_client.create_volume(
-            size=1, display_name=vol_name,
-            volume_type=vol_type_name)
+            size=1, **params)
         self.assertIn('id', volume)
         self.addCleanup(self._delete_volume, volume['id'])
-        self.assertIn('display_name', volume)
-        self.assertEqual(volume['display_name'], vol_name,
+        self.assertIn(self.name_field, volume)
+        self.assertEqual(volume[self.name_field], vol_name,
                          "The created volume name is not equal "
                          "to the requested name")
         self.assertTrue(volume['id'] is not None,
                         "Field volume id is empty or not found.")
-        self.volumes_client.wait_for_volume_status(volume['id'],
-                                                   'available')
+        self.volumes_client.wait_for_volume_status(volume['id'], 'available')
         _, fetched_volume = self.volumes_client.get_volume(volume['id'])
-        self.assertEqual(vol_name, fetched_volume['display_name'],
+        self.assertEqual(vol_name, fetched_volume[self.name_field],
                          'The fetched Volume is different '
                          'from the created Volume')
         self.assertEqual(volume['id'], fetched_volume['id'],
@@ -154,3 +154,7 @@
             self.volume_types_client.get_encryption_type(
                 encryption_type['volume_type_id']))
         self.assertEmpty(deleted_encryption_type)
+
+
+class VolumeTypesV1Test(VolumeTypesV2Test):
+    _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index a4d6431..9c9913f 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -20,16 +20,18 @@
 from tempest import test
 
 
-class VolumeTypesNegativeTest(base.BaseVolumeV1AdminTest):
+class VolumeTypesNegativeV2Test(base.BaseVolumeAdminTest):
     _interface = 'json'
 
     @test.attr(type='gate')
     def test_create_with_nonexistent_volume_type(self):
         # Should not be able to create volume with nonexistent volume_type.
+        self.name_field = self.special_fields['name_field']
+        params = {self.name_field: str(uuid.uuid4()),
+                  'volume_type': str(uuid.uuid4())}
         self.assertRaises(exceptions.NotFound,
                           self.volumes_client.create_volume, size=1,
-                          display_name=str(uuid.uuid4()),
-                          volume_type=str(uuid.uuid4()))
+                          **params)
 
     @test.attr(type='gate')
     def test_create_with_empty_name(self):
@@ -52,5 +54,9 @@
                           str(uuid.uuid4()))
 
 
-class VolumesTypesNegativeTestXML(VolumeTypesNegativeTest):
+class VolumeTypesNegativeV1Test(VolumeTypesNegativeV2Test):
+    _api_version = 1
+
+
+class VolumeTypesNegativeV1TestXML(VolumeTypesNegativeV1Test):
     _interface = 'xml'
diff --git a/tempest/cli/simple_read_only/volume/test_cinder.py b/tempest/cli/simple_read_only/volume/test_cinder.py
index 6e1e7d3..102f199 100644
--- a/tempest/cli/simple_read_only/volume/test_cinder.py
+++ b/tempest/cli/simple_read_only/volume/test_cinder.py
@@ -137,8 +137,7 @@
     def test_cinder_service_list(self):
         service_list = self.parser.listing(self.cinder('service-list'))
         self.assertTableStruct(service_list, ['Binary', 'Host', 'Zone',
-                                              'Status', 'State', 'Updated_at',
-                                              'Disabled Reason'])
+                                              'Status', 'State', 'Updated_at'])
 
     def test_cinder_transfer_list(self):
         transfer_list = self.parser.listing(self.cinder('transfer-list'))
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 2ebfdd1..ecca5ee 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -475,9 +475,9 @@
 
     @classmethod
     def resource_setup(cls):
+        cls.check_preconditions()
         super(NetworkScenarioTest, cls).resource_setup()
         cls.tenant_id = cls.manager.identity_client.tenant_id
-        cls.check_preconditions()
 
     def _create_network(self, client=None, tenant_id=None,
                         namestart='network-smoke-'):
@@ -1022,12 +1022,11 @@
 class BaremetalScenarioTest(ScenarioTest):
     @classmethod
     def resource_setup(cls):
-        super(BaremetalScenarioTest, cls).resource_setup()
-
         if (not CONF.service_available.ironic or
            not CONF.baremetal.driver_enabled):
             msg = 'Ironic not available or Ironic compute driver not enabled'
             raise cls.skipException(msg)
+        super(BaremetalScenarioTest, cls).resource_setup()
 
         # use an admin client manager for baremetal client
         manager = clients.Manager(
@@ -1201,9 +1200,9 @@
 
     @classmethod
     def resource_setup(cls):
-        super(OrchestrationScenarioTest, cls).resource_setup()
         if not CONF.service_available.heat:
             raise cls.skipException("Heat support is required")
+        super(OrchestrationScenarioTest, cls).resource_setup()
 
     @classmethod
     def credentials(cls):
@@ -1246,12 +1245,12 @@
 
     @classmethod
     def resource_setup(cls):
-        cls.set_network_resources()
-        super(SwiftScenarioTest, cls).resource_setup()
         if not CONF.service_available.swift:
             skip_msg = ("%s skipped as swift is not available" %
                         cls.__name__)
             raise cls.skipException(skip_msg)
+        cls.set_network_resources()
+        super(SwiftScenarioTest, cls).resource_setup()
         # Clients for Swift
         cls.account_client = cls.manager.account_client
         cls.container_client = cls.manager.container_client
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index f218fb2..875a1d9 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -35,11 +35,10 @@
 
     @classmethod
     def resource_setup(cls):
-        cls.set_network_resources()
-        super(TestDashboardBasicOps, cls).resource_setup()
-
         if not CONF.service_available.horizon:
             raise cls.skipException("Horizon support is required")
+        cls.set_network_resources()
+        super(TestDashboardBasicOps, cls).resource_setup()
 
     def check_login_page(self):
         response = urllib2.urlopen(CONF.dashboard.dashboard_url)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index ac4f004..e3f87e9 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -89,13 +89,13 @@
 
     @classmethod
     def resource_setup(cls):
-        # Create no network resources for these tests.
-        cls.set_network_resources()
-        super(TestNetworkBasicOps, cls).resource_setup()
         for ext in ['router', 'security-group']:
             if not test.is_extension_enabled(ext, 'network'):
                 msg = "%s extension not enabled." % ext
                 raise cls.skipException(msg)
+        # Create no network resources for these tests.
+        cls.set_network_resources()
+        super(TestNetworkBasicOps, cls).resource_setup()
 
     def setUp(self):
         super(TestNetworkBasicOps, self).setUp()
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 6c36034..6ea3253 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -120,16 +120,6 @@
             cls.enabled = False
             raise cls.skipException(msg)
         super(TestSecurityGroupsBasicOps, cls).check_preconditions()
-        # need alt_creds here to check preconditions
-        cls.alt_creds = cls.alt_credentials()
-        cls.alt_manager = clients.Manager(cls.alt_creds)
-        # Credentials from the manager are filled with both IDs and Names
-        cls.alt_creds = cls.alt_manager.credentials
-        if (cls.alt_creds is None) or \
-                (cls.tenant_id is cls.alt_creds.tenant_id):
-            msg = 'No alt_tenant defined'
-            cls.enabled = False
-            raise cls.skipException(msg)
         if not (CONF.network.tenant_networks_reachable or
                 CONF.network.public_network_id):
             msg = ('Either tenant_networks_reachable must be "true", or '
@@ -144,6 +134,13 @@
         super(TestSecurityGroupsBasicOps, cls).resource_setup()
         # TODO(mnewby) Consider looking up entities as needed instead
         # of storing them as collections on the class.
+
+        # get credentials for secondary tenant
+        cls.alt_creds = cls.isolated_creds.get_alt_creds()
+        cls.alt_manager = clients.Manager(cls.alt_creds)
+        # Credentials from the manager are filled with both IDs and Names
+        cls.alt_creds = cls.alt_manager.credentials
+
         cls.floating_ips = {}
         cls.tenants = {}
         creds = cls.credentials()
@@ -437,6 +434,8 @@
     @test.attr(type='smoke')
     @test.services('compute', 'network')
     def test_cross_tenant_traffic(self):
+        if not self.isolated_creds.is_multi_tenant():
+            raise self.skipException("No secondary tenant defined")
         try:
             # deploy new tenant
             self._deploy_tenant(self.alt_tenant)
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index c53e22b..d10fcce 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -36,12 +36,11 @@
 
     @classmethod
     def resource_setup(cls):
-        cls.set_network_resources()
-        super(TestServerAdvancedOps, cls).resource_setup()
-
         if CONF.compute.flavor_ref_alt == CONF.compute.flavor_ref:
             msg = "Skipping test - flavor_ref and flavor_ref_alt are identical"
             raise cls.skipException(msg)
+        cls.set_network_resources()
+        super(TestServerAdvancedOps, cls).resource_setup()
 
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize is not available.')
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 7fc1edf..e30c824 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -52,10 +52,9 @@
 
     @classmethod
     def resource_setup(cls):
-        super(TestStampPattern, cls).resource_setup()
-
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder volume snapshots are disabled")
+        super(TestStampPattern, cls).resource_setup()
 
     def _wait_for_volume_snapshot_status(self, volume_snapshot, status):
         self.snapshots_client.wait_for_snapshot_status(volume_snapshot['id'],
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index a20db5c..62876c4 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -37,10 +37,9 @@
     """
     @classmethod
     def resource_setup(cls):
-        super(TestVolumeBootPattern, cls).resource_setup()
-
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder volume snapshots are disabled")
+        super(TestVolumeBootPattern, cls).resource_setup()
 
     def _create_volume_from_image(self):
         img_uuid = CONF.compute.image_ref
diff --git a/tempest/services/volume/xml/admin/volume_types_client.py b/tempest/services/volume/xml/admin/volume_types_client.py
index 2464016..03d39a8 100644
--- a/tempest/services/volume/xml/admin/volume_types_client.py
+++ b/tempest/services/volume/xml/admin/volume_types_client.py
@@ -25,14 +25,14 @@
 CONF = config.CONF
 
 
-class VolumeTypesClientXML(rest_client.RestClient):
+class BaseVolumeTypesClientXML(rest_client.RestClient):
     """
     Client class to send CRUD Volume Types API requests to a Cinder endpoint
     """
     TYPE = "xml"
 
     def __init__(self, auth_provider):
-        super(VolumeTypesClientXML, self).__init__(auth_provider)
+        super(BaseVolumeTypesClientXML, self).__init__(auth_provider)
         self.service = CONF.volume.catalog_type
         self.build_interval = CONF.compute.build_interval
         self.build_timeout = CONF.compute.build_timeout
@@ -210,3 +210,9 @@
     def resource_type(self):
         """Returns the primary type of resource this client works with."""
         return 'volume-type'
+
+
+class VolumeTypesClientXML(BaseVolumeTypesClientXML):
+    """
+    Client class to send CRUD Volume Type API V1 requests to a Cinder endpoint
+    """