Merge "skip test_list_servers_filtered_by_ip_regex on neutron gate"
diff --git a/tempest/api/README.rst b/tempest/api/README.rst
index 617fda4..9d8dc10 100644
--- a/tempest/api/README.rst
+++ b/tempest/api/README.rst
@@ -9,15 +9,15 @@
works with the OpenStack API as documented. The current largest
portion of Tempest code is devoted to test cases that do exactly this.
-It's also important to test not only the expected possitive path on
+It's also important to test not only the expected positive path on
APIs, but also to provide them with invalid data to ensure they fail
in expected and documented ways. Over the course of the OpenStack
project Tempest has discovered many fundamental bugs by doing just
this.
-In order for some APIs to return meaniful results, there must be
+In order for some APIs to return meaningful results, there must be
enough data in the system. This means these tests might start by
-spinning up a server, image, etc, then opperating on it.
+spinning up a server, image, etc, then operating on it.
Why are these tests in tempest?
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 15e28fd..acf0275 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -36,6 +36,7 @@
@classmethod
def setUpClass(cls):
+ super(BaseComputeTest, cls).setUpClass()
if not cls.config.service_available.nova:
skip_msg = ("%s skipped as nova is not available" % cls.__name__)
raise cls.skipException(skip_msg)
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index 9f7b24b..d98fb71 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -53,6 +53,7 @@
cls.client.delete_endpoint(e['id'])
for s in cls.service_ids:
cls.identity_client.delete_service(s)
+ super(EndPointsTestJSON, cls).tearDownClass()
@attr(type='gate')
def test_list_endpoints(self):
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 1237ce4..bfb5372 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -25,6 +25,7 @@
@classmethod
def setUpClass(cls):
+ super(BaseIdentityAdminTest, cls).setUpClass()
os = clients.AdminManager(interface=cls._interface)
cls.client = os.identity_client
cls.token_client = os.token_client
@@ -45,6 +46,7 @@
@classmethod
def tearDownClass(cls):
cls.data.teardown_all()
+ super(BaseIdentityAdminTest, cls).tearDownClass()
def disable_user(self, user_name):
user = self.get_user_by_name(user_name)
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 4e61495..4f54a15 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -29,6 +29,7 @@
@classmethod
def setUpClass(cls):
+ super(BaseImageTest, cls).setUpClass()
cls.created_images = []
cls._interface = 'json'
cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index d3fa763..2a3b3f7 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -47,6 +47,7 @@
@classmethod
def setUpClass(cls):
+ super(BaseNetworkTest, cls).setUpClass()
os = clients.Manager()
cls.network_cfg = os.config.network
if not cls.config.service_available.neutron:
@@ -64,6 +65,7 @@
cls.client.delete_subnet(subnet['id'])
for network in cls.networks:
cls.client.delete_network(network['id'])
+ super(BaseNetworkTest, cls).tearDownClass()
@classmethod
def create_network(cls, network_name=None):
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 5a1fb5a..820328c 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -26,6 +26,7 @@
@classmethod
def setUpClass(cls):
+ super(BaseObjectTest, cls).setUpClass()
if not cls.config.service_available.swift:
skip_msg = ("%s skipped as swift is not available" % cls.__name__)
raise cls.skipException(skip_msg)
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 8b9fc8c..eaaed39 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -31,6 +31,7 @@
@classmethod
def tearDownClass(cls):
cls.delete_containers(cls.containers)
+ super(ContainerTest, cls).tearDownClass()
@attr(type='smoke')
def test_create_container(self):
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 5de4df0..d18c2ad 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -50,6 +50,7 @@
def tearDownClass(cls):
for client in cls.clients.values():
cls.delete_containers(cls.containers, client[0], client[1])
+ super(ContainerSyncTest, cls).tearDownClass()
@testtools.skip('Until Bug #1093743 is resolved.')
@attr(type='gate')
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index b546cec..8703480 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -41,6 +41,7 @@
NotFound exception and also non empty container cannot be deleted.
"""
cls.delete_containers([cls.container_name])
+ super(ObjectExpiryTest, cls).tearDownClass()
@testtools.skip('Until Bug #1069849 is resolved.')
@attr(type='gate')
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index c8d9965..c599562 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -47,6 +47,7 @@
cls.delete_containers(cls.containers)
# delete the user setup created
cls.data.teardown_all()
+ super(ObjectTest, cls).tearDownClass()
@attr(type='smoke')
def test_create_object(self):
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index cda3e4f..2b93c32 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -29,6 +29,7 @@
@classmethod
def tearDownClass(cls):
cls.delete_containers(cls.containers)
+ super(ContainerTest, cls).tearDownClass()
def assertContainer(self, container, count, byte, versioned):
resp, _ = self.container_client.list_container_metadata(container)
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index d06d942..745dd87 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -28,7 +28,7 @@
@classmethod
def setUpClass(cls):
-
+ super(BaseOrchestrationTest, cls).setUpClass()
os = clients.OrchestrationManager()
cls.orchestration_cfg = os.config.orchestration
if not os.config.service_available.heat:
@@ -107,6 +107,7 @@
def tearDownClass(cls):
cls.clear_stacks()
cls.clear_keypairs()
+ super(BaseOrchestrationTest, cls).tearDownClass()
def wait_for(self, condition):
"""Repeatedly calls condition() until a timeout."""
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 52ab5b7..7781647 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -31,6 +31,7 @@
@classmethod
def setUpClass(cls):
+ super(BaseVolumeTest, cls).setUpClass()
cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
if not cls.config.service_available.cinder:
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 4447da0..d0f0127 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -150,6 +150,7 @@
@classmethod
def setUpClass(cls):
+ super(OfficialClientTest, cls).setUpClass()
cls.isolated_creds = isolated_creds.IsolatedCreds(
__name__, tempest_client=False)
if cls.config.compute.allow_tenant_isolation:
diff --git a/tempest/services/compute/xml/flavors_client.py b/tempest/services/compute/xml/flavors_client.py
index 6ba31ea..3a8986c 100644
--- a/tempest/services/compute/xml/flavors_client.py
+++ b/tempest/services/compute/xml/flavors_client.py
@@ -30,6 +30,8 @@
"http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1"
XMLNS_OS_FLV_ACCESS = \
"http://docs.openstack.org/compute/ext/flavor_access/api/v1.1"
+XMLNS_OS_FLV_WITH_EXT_SPECS = \
+ "http://docs.openstack.org/compute/ext/flavor_with_extra_specs/api/v2.0"
class FlavorsClientXML(RestClientXML):
@@ -49,6 +51,11 @@
if k == '{%s}ephemeral' % XMLNS_OS_FLV_EXT_DATA:
k = 'OS-FLV-EXT-DATA:ephemeral'
+ if k == '{%s}extra_specs' % XMLNS_OS_FLV_WITH_EXT_SPECS:
+ k = 'OS-FLV-WITH-EXT-SPECS:extra_specs'
+ flavor[k] = dict(v)
+ continue
+
try:
v = int(v)
except ValueError:
diff --git a/tempest/test.py b/tempest/test.py
index 0cd0b08..7787790 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import atexit
import os
import time
@@ -91,6 +92,17 @@
LOG.info("Overriding skipException to nose SkipTest")
testtools.TestCase.skipException = nose.plugins.skip.SkipTest
+at_exit_set = set()
+
+
+def validate_tearDownClass():
+ if at_exit_set:
+ raise RuntimeError("tearDownClass does not calls the super's"
+ "tearDownClass in these classes: "
+ + str(at_exit_set))
+
+atexit.register(validate_tearDownClass)
+
class BaseTestCase(testtools.TestCase,
testtools.testcase.WithAttributes,
@@ -98,29 +110,43 @@
config = config.TempestConfig()
+ setUpClassCalled = False
+
@classmethod
def setUpClass(cls):
if hasattr(super(BaseTestCase, cls), 'setUpClass'):
super(BaseTestCase, cls).setUpClass()
+ cls.setUpClassCalled = True
- def setUp(cls):
- super(BaseTestCase, cls).setUp()
+ @classmethod
+ def tearDownClass(cls):
+ at_exit_set.remove(cls)
+ if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
+ super(BaseTestCase, cls).tearDownClass()
+
+ def setUp(self):
+ super(BaseTestCase, self).setUp()
+ if not self.setUpClassCalled:
+ raise RuntimeError("setUpClass does not calls the super's"
+ "setUpClass in the "
+ + self.__class__.__name__)
+ at_exit_set.add(self.__class__)
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
try:
test_timeout = int(test_timeout)
except ValueError:
test_timeout = 0
if test_timeout > 0:
- cls.useFixture(fixtures.Timeout(test_timeout, gentle=True))
+ self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
os.environ.get('OS_STDOUT_CAPTURE') == '1'):
- stdout = cls.useFixture(fixtures.StringStream('stdout')).stream
- cls.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
+ stdout = self.useFixture(fixtures.StringStream('stdout')).stream
+ self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
os.environ.get('OS_STDERR_CAPTURE') == '1'):
- stderr = cls.useFixture(fixtures.StringStream('stderr')).stream
- cls.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
+ stderr = self.useFixture(fixtures.StringStream('stderr')).stream
+ self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
@classmethod
def _get_identity_admin_client(cls):
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index 8812a10..e0c9f06 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -197,6 +197,7 @@
@classmethod
def setUpClass(cls):
+ super(BotoTestCase, cls).setUpClass()
# The trash contains cleanup functions and paramaters in tuples
# (function, *args, **kwargs)
cls._resource_trash_bin = {}
@@ -261,6 +262,10 @@
LOG.exception(exc)
finally:
del cls._resource_trash_bin[key]
+ super(BotoTestCase, cls).tearDownClass()
+ # NOTE(afazekas): let the super called even on exceptions
+ # The real exceptions already logged, if the super throws another,
+ # does not causes hidden issues
if fail_count:
raise exceptions.TearDownException(num=fail_count)