Merge "Enable cinder v2 api for volume hosts"
diff --git a/README.rst b/README.rst
index ea36619..5284bbf 100644
--- a/README.rst
+++ b/README.rst
@@ -79,8 +79,10 @@
 document. The etc/tempest.conf.sample attempts to be a self
 documenting version of the configuration.
 
-The sample config file is auto generated using the script:
-tools/generate_sample.sh
+To generate the sample tempest.conf file, run the following
+command from the top level of the tempest directory:
+
+  tox -egenconfig
 
 The most important pieces that are needed are the user ids, openstack
 endpoints, and basic flavors and images needed to run tests.
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 9a9952d..d5311a9 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -758,8 +758,10 @@
 # value)
 #public_network_id =
 
-# Id of the public router that provides external connectivity (string
-# value)
+# Id of the public router that provides external connectivity. This
+# should only be used when Neutron's 'allow_overlapping_ips' is set to
+# 'False' in neutron.conf. usually not needed past 'Grizzly' release
+# (string value)
 #public_router_id =
 
 # The network region name to use. If empty, the value of
diff --git a/requirements.txt b/requirements.txt
index ac72017..a856d09 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,20 +5,20 @@
 anyjson>=0.3.3
 httplib2>=0.7.5
 jsonschema>=2.0.0,<3.0.0
-testtools>=0.9.34
+testtools>=0.9.36,!=1.2.0,!=1.4.0
 lxml>=2.3
 boto>=2.32.1
 paramiko>=1.13.0
 netaddr>=0.7.12
 python-ceilometerclient>=1.0.6
 python-glanceclient>=0.14.0
-python-keystoneclient>=0.10.0
+python-keystoneclient>=0.11.1
 python-novaclient>=2.18.0
 python-neutronclient>=2.3.6,<3
 python-cinderclient>=1.1.0
 python-heatclient>=0.2.9
 python-ironicclient>=0.2.1
-python-saharaclient>=0.7.3
+python-saharaclient>=0.7.5
 python-swiftclient>=2.2.0
 testresources>=0.2.4
 testrepository>=0.0.18
diff --git a/tempest/api/compute/servers/test_servers_negative_new.py b/tempest/api/compute/servers/test_servers_negative_new.py
deleted file mode 100644
index 7fc2d4f..0000000
--- a/tempest/api/compute/servers/test_servers_negative_new.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2014 Red Hat, Inc & Deutsche Telekom AG
-# 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.api.compute import base
-from tempest.api_schema.request.compute.v2 import servers
-from tempest import test
-
-
-load_tests = test.NegativeAutoTest.load_tests
-
-
-@test.SimpleNegativeAutoTest
-class GetConsoleOutputNegativeTestJSON(base.BaseV2ComputeTest,
-                                       test.NegativeAutoTest):
-    _service = 'compute'
-    _schema = servers.get_console_output
-
-    @classmethod
-    def resource_setup(cls):
-        super(GetConsoleOutputNegativeTestJSON, cls).resource_setup()
-        _resp, server = cls.create_test_server()
-        cls.set_resource("server", server['id'])
diff --git a/tempest/config.py b/tempest/config.py
index 6e8238a..163817c 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -449,7 +449,9 @@
     cfg.StrOpt('public_router_id',
                default="",
                help="Id of the public router that provides external "
-                    "connectivity"),
+                    "connectivity. This should only be used when Neutron's "
+                    "'allow_overlapping_ips' is set to 'False' in "
+                    "neutron.conf. usually not needed past 'Grizzly' release"),
     cfg.IntOpt('build_timeout',
                default=300,
                help="Timeout in seconds to wait for network operation to "
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index ecca5ee..ea4365e 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -1268,6 +1268,9 @@
         # look for the container to assure it is created
         self.list_and_check_container_objects(name)
         LOG.debug('Container %s created' % (name))
+        self.addCleanup(self.delete_wrapper,
+                        self.container_client.delete_container,
+                        name)
         return name
 
     def delete_container(self, container_name):
@@ -1278,6 +1281,10 @@
         obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
         obj_data = data_utils.arbitrary_string()
         self.object_client.create_object(container_name, obj_name, obj_data)
+        self.addCleanup(self.delete_wrapper,
+                        self.object_client.delete_object,
+                        container_name,
+                        obj_name)
         return obj_name, obj_data
 
     def delete_object(self, container_name, filename):
diff --git a/tempest/scenario/test_swift_basic_ops.py b/tempest/scenario/test_swift_basic_ops.py
index 9e0fee0..fcb9505 100644
--- a/tempest/scenario/test_swift_basic_ops.py
+++ b/tempest/scenario/test_swift_basic_ops.py
@@ -44,9 +44,12 @@
         self.get_swift_stat()
         container_name = self.create_container()
         obj_name, obj_data = self.upload_object_to_container(container_name)
-        self.list_and_check_container_objects(container_name, [obj_name])
+        self.list_and_check_container_objects(container_name,
+                                              present_obj=[obj_name])
         self.download_and_verify(container_name, obj_name, obj_data)
         self.delete_object(container_name, obj_name)
+        self.list_and_check_container_objects(container_name,
+                                              not_present_obj=[obj_name])
         self.delete_container(container_name)
 
     @test.services('object_storage')
@@ -68,5 +71,3 @@
         self.change_container_acl(container_name, '.r:*')
         resp, _ = http_client.request(obj_url, 'GET')
         self.assertEqual(resp.status, 200)
-        self.delete_object(container_name, obj_name)
-        self.delete_container(container_name)
diff --git a/tempest/scenario/utils.py b/tempest/scenario/utils.py
index c20f20c..e6624a3 100644
--- a/tempest/scenario/utils.py
+++ b/tempest/scenario/utils.py
@@ -25,6 +25,7 @@
 from tempest import clients
 from tempest.common.utils import misc
 from tempest import config
+from tempest import exceptions
 
 CONF = config.CONF
 
@@ -151,9 +152,12 @@
         loader, standard_tests, pattern = args
     else:
         standard_tests, module, loader = args
-    scenario_utils = InputScenarioUtils()
-    scenario_flavor = scenario_utils.scenario_flavors
-    scenario_image = scenario_utils.scenario_images
+    try:
+        scenario_utils = InputScenarioUtils()
+        scenario_flavor = scenario_utils.scenario_flavors
+        scenario_image = scenario_utils.scenario_images
+    except exceptions.InvalidConfiguration:
+        return standard_tests
     for test in testtools.iterate_tests(standard_tests):
         setattr(test, 'scenarios', testscenarios.multiply_scenarios(
             scenario_image,
diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py
index 157fc5f..efdb413 100644
--- a/tempest/tests/test_list_tests.py
+++ b/tempest/tests/test_list_tests.py
@@ -12,6 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import os
 import re
 import subprocess
 
@@ -20,16 +21,23 @@
 
 class TestTestList(base.TestCase):
 
-    def test_no_import_errors(self):
+    def test_testr_list_tests_no_errors(self):
+        # Remove unit test discover path from env to test tempest tests
+        test_env = os.environ.copy()
+        test_env.pop('OS_TEST_PATH')
         import_failures = []
-        p = subprocess.Popen(['testr', 'list-tests'], stdout=subprocess.PIPE)
-        ids = p.stdout.read()
+        p = subprocess.Popen(['testr', 'list-tests'], stdout=subprocess.PIPE,
+                             env=test_env)
+        ids, err = p.communicate()
+        self.assertEqual(0, p.returncode,
+                         "test discovery failed, one or more files cause an "
+                         "error on import")
         ids = ids.split('\n')
         for test_id in ids:
             if re.match('(\w+\.){3}\w+', test_id):
                 if not test_id.startswith('tempest.'):
-                    fail_id = test_id.split('unittest.loader.ModuleImport'
-                                            'Failure.')[1]
+                    parts = test_id.partition('tempest')
+                    fail_id = parts[1] + parts[2]
                     import_failures.append(fail_id)
         error_message = ("The following tests have import failures and aren't"
                          " being run with test filters %s" % import_failures)
diff --git a/test-requirements.txt b/test-requirements.txt
index ba70259..6eefeee 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,11 +3,11 @@
 # process, which may cause wedges in the gate later.
 hacking>=0.9.2,<0.10
 # needed for doc build
-sphinx>=1.1.2,!=1.2.0,<1.3
+sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
 python-subunit>=0.0.18
 oslosphinx>=2.2.0  # Apache-2.0
 mox>=0.5.3
 mock>=1.0
 coverage>=3.6
-oslotest>=1.1.0  # Apache-2.0
-stevedore>=1.0.0  # Apache-2.0
+oslotest>=1.2.0  # Apache-2.0
+stevedore>=1.1.0  # Apache-2.0