Merge "Use random binary data for test images"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 8a7ad9c..f80fc1b 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -391,12 +391,14 @@
# A list of enabled compute extensions with a special entry
# all which indicates every extension is enabled. Each
-# extension should be specified with alias name (list value)
+# extension should be specified with alias name. Empty list
+# indicates all extensions are disabled (list value)
#api_extensions=all
# A list of enabled v3 extensions with a special entry all
# which indicates every extension is enabled. Each extension
-# should be specified with alias name (list value)
+# should be specified with alias name. Empty list indicates
+# all extensions are disabled (list value)
#api_v3_extensions=all
# Does the test environment support changing the admin
@@ -441,6 +443,11 @@
# (boolean value)
#rescue=true
+# Enables returning of the instance password by the relevant
+# server API calls such as create, rebuild or rescue. (boolean
+# value)
+#enable_instance_password=true
+
[dashboard]
@@ -750,7 +757,8 @@
#ipv6=true
# A list of enabled network extensions with a special entry
-# all which indicates every extension is enabled (list value)
+# all which indicates every extension is enabled. Empty list
+# indicates all extensions are disabled (list value)
#api_extensions=all
# Allow the execution of IPv6 subnet tests that use the
@@ -1105,7 +1113,8 @@
#snapshot=true
# A list of enabled volume extensions with a special entry all
-# which indicates every extension is enabled (list value)
+# which indicates every extension is enabled. Empty list
+# indicates all extensions are disabled (list value)
#api_extensions=all
# Is the v1 volume API enabled (boolean value)
diff --git a/tempest/README.rst b/tempest/README.rst
index 18c7cf3..fb25151 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -23,9 +23,8 @@
belongs in each directory, the rules and examples for good tests, are
documented in a README.rst file in the directory.
-
-api
----
+:ref:`api_field_guide`
+----------------------
API tests are validation tests for the OpenStack API. They should not
use the existing python clients for OpenStack, but should instead use
@@ -39,8 +38,8 @@
frameworks.
-cli
----
+:ref:`cli_field_guide`
+----------------------
CLI tests use the openstack CLI to interact with the OpenStack
cloud. CLI testing in unit tests is somewhat difficult because unlike
@@ -49,8 +48,8 @@
prereqs having a running OpenStack cloud.
-scenario
---------
+:ref:`scenario_field_guide`
+---------------------------
Scenario tests are complex "through path" tests for OpenStack
functionality. They are typically a series of steps where complicated
@@ -59,18 +58,26 @@
Scenario tests can and should use the OpenStack python clients.
-stress
-------
+:ref:`stress_field_guide`
+-------------------------
Stress tests are designed to stress an OpenStack environment by running a high
workload against it and seeing what breaks. The stress test framework runs
several test jobs in parallel and can run any existing test in Tempest as a
stress job.
-thirdparty
-----------
+:ref:`third_party_field_guide`
+-----------------------------
Many openstack components include 3rdparty API support. It is
completely legitimate for Tempest to include tests of 3rdparty APIs,
but those should be kept separate from the normal OpenStack
validation.
+
+:ref:`unit_tests_field_guide`
+-----------------------------
+
+Unit tests are the self checks for Tempest. They provide functional
+verification and regression checking for the internal components of tempest.
+They should be used to just verify that the individual pieces of tempest are
+working as expected.
diff --git a/tempest/api/README.rst b/tempest/api/README.rst
index 9eac19d..91e6ad6 100644
--- a/tempest/api/README.rst
+++ b/tempest/api/README.rst
@@ -1,3 +1,5 @@
+.. _api_field_guide:
+
Tempest Field Guide to API tests
================================
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index f147b9c..599b058 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -111,7 +111,9 @@
security_groups=default_sg_quota)
# Check we cannot create anymore
- self.assertRaises(exceptions.OverLimit,
+ # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+ # will be raised when out of quota
+ self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
self.sg_client.create_security_group,
"sg-overlimit", "sg-desc")
@@ -147,7 +149,9 @@
ip_protocol = 'tcp'
# Check we cannot create SG rule anymore
- self.assertRaises(exceptions.OverLimit,
+ # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+ # will be raised when out of quota
+ self.assertRaises((exceptions.OverLimit, exceptions.Unauthorized),
self.sg_client.create_security_group_rule,
secgroup_id, ip_protocol, 1025, 1025)
diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py
index b55833c..fbda401 100644
--- a/tempest/api/compute/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/servers/test_server_metadata_negative.py
@@ -119,20 +119,22 @@
@test.attr(type=['negative', 'gate'])
def test_metadata_items_limit(self):
- # Raise a 413 OverLimit exception while exceeding metadata items limit
- # for tenant.
+ # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+ # will be raised while exceeding metadata items limit for
+ # tenant.
_, quota_set = self.quotas.get_quota_set(self.tenant_id)
quota_metadata = quota_set['metadata_items']
req_metadata = {}
for num in range(1, quota_metadata + 2):
req_metadata['key' + str(num)] = 'val' + str(num)
- self.assertRaises(exceptions.OverLimit,
+ self.assertRaises((exceptions.OverLimit, exceptions.Unauthorized),
self.client.set_server_metadata,
self.server_id, req_metadata)
- # Raise a 413 OverLimit exception while exceeding metadata items limit
- # for tenant (update).
- self.assertRaises(exceptions.OverLimit,
+ # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+ # will be raised while exceeding metadata items limit for
+ # tenant.
+ self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
self.client.update_server_metadata,
self.server_id, req_metadata)
diff --git a/tempest/api/orchestration/stacks/test_stacks.py b/tempest/api/orchestration/stacks/test_stacks.py
index 5b45d82..d5e66e8 100644
--- a/tempest/api/orchestration/stacks/test_stacks.py
+++ b/tempest/api/orchestration/stacks/test_stacks.py
@@ -64,3 +64,4 @@
# delete the stack
resp = self.client.delete_stack(stack_identifier)
self.assertEqual('204', resp[0]['status'])
+ self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index c5be1f3..abf3c6b 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -61,12 +61,20 @@
cls.volumes_extension_client = cls.os.volumes_extension_client
cls.availability_zone_client = (
cls.os.volume_availability_zone_client)
+ # Special fields and resp code for cinder v1
+ cls.special_fields = {'name_field': 'display_name',
+ 'descrip_field': 'display_description',
+ 'create_resp': 200}
elif cls._api_version == 2:
if not CONF.volume_feature_enabled.api_v2:
msg = "Volume API v2 is disabled"
raise cls.skipException(msg)
cls.volumes_client = cls.os.volumes_v2_client
+ # Special fields and resp code for cinder v2
+ cls.special_fields = {'name_field': 'name',
+ 'descrip_field': 'description',
+ 'create_resp': 202}
else:
msg = ("Invalid Cinder API version (%s)" % cls._api_version)
@@ -82,15 +90,15 @@
@classmethod
def create_volume(cls, size=1, **kwargs):
"""Wrapper utility that returns a test volume."""
- vol_name = data_utils.rand_name('Volume')
- if cls._api_version == 1:
- resp, volume = cls.volumes_client.create_volume(
- size, display_name=vol_name, **kwargs)
- assert 200 == resp.status
- elif cls._api_version == 2:
- resp, volume = cls.volumes_client.create_volume(
- size, name=vol_name, **kwargs)
- assert 202 == resp.status
+ name = data_utils.rand_name('Volume')
+
+ name_field = cls.special_fields['name_field']
+ expect_status = cls.special_fields['create_resp']
+
+ kwargs[name_field] = name
+ resp, volume = cls.volumes_client.create_volume(size, **kwargs)
+ assert expect_status == resp.status
+
cls.volumes.append(volume)
cls.volumes_client.wait_for_volume_status(volume['id'], 'available')
return volume
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index 0d57d47..0505f19 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -19,13 +19,12 @@
from tempest import test
-class VolumeMetadataTest(base.BaseVolumeV1Test):
- _interface = "json"
+class VolumesV2MetadataTest(base.BaseVolumeTest):
@classmethod
@test.safe_setup
def setUpClass(cls):
- super(VolumeMetadataTest, cls).setUpClass()
+ super(VolumesV2MetadataTest, cls).setUpClass()
# Create a volume
cls.volume = cls.create_volume()
cls.volume_id = cls.volume['id']
@@ -33,7 +32,7 @@
def tearDown(self):
# Update the metadata to {}
self.volumes_client.update_volume_metadata(self.volume_id, {})
- super(VolumeMetadataTest, self).tearDown()
+ super(VolumesV2MetadataTest, self).tearDown()
@test.attr(type='gate')
def test_create_get_delete_volume_metadata(self):
@@ -117,5 +116,13 @@
self.assertThat(body.items(), matchers.ContainsAll(expect.items()))
-class VolumeMetadataTestXML(VolumeMetadataTest):
+class VolumesV2MetadataTestXML(VolumesV2MetadataTest):
+ _interface = "xml"
+
+
+class VolumesV1MetadataTest(VolumesV2MetadataTest):
+ _api_version = 1
+
+
+class VolumesV1MetadataTestXML(VolumesV1MetadataTest):
_interface = "xml"
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 82d1364..bf61222 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -23,12 +23,11 @@
CONF = config.CONF
-class VolumesTransfersTest(base.BaseVolumeV1Test):
- _interface = "json"
+class VolumesV2TransfersTest(base.BaseVolumeTest):
@classmethod
def setUpClass(cls):
- super(VolumesTransfersTest, cls).setUpClass()
+ super(VolumesV2TransfersTest, cls).setUpClass()
# Add another tenant to test volume-transfer
if CONF.compute.allow_tenant_isolation:
@@ -110,5 +109,13 @@
self.client.wait_for_volume_status(volume['id'], 'available')
-class VolumesTransfersTestXML(VolumesTransfersTest):
+class VolumesV2TransfersTestXML(VolumesV2TransfersTest):
+ _interface = "xml"
+
+
+class VolumesV1TransfersTest(VolumesV2TransfersTest):
+ _api_version = 1
+
+
+class VolumesV1TransfersTestXML(VolumesV1TransfersTest):
_interface = "xml"
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index cfab0bd..6fef564 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -21,13 +21,12 @@
CONF = config.CONF
-class VolumesActionsTest(base.BaseVolumeV1Test):
- _interface = "json"
+class VolumesV2ActionsTest(base.BaseVolumeTest):
@classmethod
@test.safe_setup
def setUpClass(cls):
- super(VolumesActionsTest, cls).setUpClass()
+ super(VolumesV2ActionsTest, cls).setUpClass()
cls.client = cls.volumes_client
cls.image_client = cls.os.image_client
@@ -47,7 +46,7 @@
cls.servers_client.delete_server(cls.server['id'])
cls.servers_client.wait_for_server_termination(cls.server['id'])
- super(VolumesActionsTest, cls).tearDownClass()
+ super(VolumesV2ActionsTest, cls).tearDownClass()
@test.stresstest(class_setup_per='process')
@test.attr(type='smoke')
@@ -165,5 +164,13 @@
self.assertEqual(False, bool_flag)
-class VolumesActionsTestXML(VolumesActionsTest):
+class VolumesV2ActionsTestXML(VolumesV2ActionsTest):
+ _interface = "xml"
+
+
+class VolumesV1ActionsTest(VolumesV2ActionsTest):
+ _api_version = 1
+
+
+class VolumesV1ActionsTestXML(VolumesV1ActionsTest):
_interface = "xml"
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 2745b95..82208aa 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -23,14 +23,17 @@
CONF = config.CONF
-class VolumesGetTest(base.BaseVolumeV1Test):
- _interface = "json"
+class VolumesV2GetTest(base.BaseVolumeTest):
@classmethod
def setUpClass(cls):
- super(VolumesGetTest, cls).setUpClass()
+ super(VolumesV2GetTest, cls).setUpClass()
cls.client = cls.volumes_client
+ cls.name_field = cls.special_fields['name_field']
+ cls.descrip_field = cls.special_fields['descrip_field']
+ cls.create_resp = cls.special_fields['create_resp']
+
def _delete_volume(self, volume_id):
resp, _ = self.client.delete_volume(volume_id)
self.assertEqual(202, resp.status)
@@ -51,24 +54,24 @@
v_name = data_utils.rand_name('Volume')
metadata = {'Type': 'Test'}
# Create a volume
- resp, volume = self.client.create_volume(display_name=v_name,
- metadata=metadata,
- **kwargs)
- self.assertEqual(200, resp.status)
+ kwargs[self.name_field] = v_name
+ kwargs['metadata'] = metadata
+ resp, volume = self.client.create_volume(**kwargs)
+ self.assertEqual(self.create_resp, resp.status)
self.assertIn('id', volume)
self.addCleanup(self._delete_volume, volume['id'])
- self.assertIn('display_name', volume)
- self.assertEqual(volume['display_name'], v_name,
+ self.client.wait_for_volume_status(volume['id'], 'available')
+ self.assertIn(self.name_field, volume)
+ self.assertEqual(volume[self.name_field], v_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.client.wait_for_volume_status(volume['id'], 'available')
# Get Volume information
resp, fetched_volume = self.client.get_volume(volume['id'])
self.assertEqual(200, resp.status)
self.assertEqual(v_name,
- fetched_volume['display_name'],
+ fetched_volume[self.name_field],
'The fetched Volume name is different '
'from the created Volume')
self.assertEqual(volume['id'],
@@ -90,27 +93,25 @@
# Update Volume
# Test volume update when display_name is same with original value
- resp, update_volume = \
- self.client.update_volume(volume['id'],
- display_name=v_name)
+ params = {self.name_field: v_name}
+ resp, update_volume = self.client.update_volume(volume['id'], **params)
self.assertEqual(200, resp.status)
# Test volume update when display_name is new
new_v_name = data_utils.rand_name('new-Volume')
new_desc = 'This is the new description of volume'
- resp, update_volume = \
- self.client.update_volume(volume['id'],
- display_name=new_v_name,
- display_description=new_desc)
+ params = {self.name_field: new_v_name,
+ self.descrip_field: new_desc}
+ resp, update_volume = self.client.update_volume(volume['id'], **params)
# Assert response body for update_volume method
self.assertEqual(200, resp.status)
- self.assertEqual(new_v_name, update_volume['display_name'])
- self.assertEqual(new_desc, update_volume['display_description'])
+ self.assertEqual(new_v_name, update_volume[self.name_field])
+ self.assertEqual(new_desc, update_volume[self.descrip_field])
# Assert response body for get_volume method
resp, updated_volume = self.client.get_volume(volume['id'])
self.assertEqual(200, resp.status)
self.assertEqual(volume['id'], updated_volume['id'])
- self.assertEqual(new_v_name, updated_volume['display_name'])
- self.assertEqual(new_desc, updated_volume['display_description'])
+ self.assertEqual(new_v_name, updated_volume[self.name_field])
+ self.assertEqual(new_desc, updated_volume[self.descrip_field])
self.assertThat(updated_volume['metadata'].items(),
matchers.ContainsAll(metadata.items()),
'The fetched Volume metadata misses data '
@@ -120,20 +121,18 @@
# then test volume update if display_name is duplicated
new_volume = {}
new_v_desc = data_utils.rand_name('@#$%^* description')
- resp, new_volume = \
- self.client.create_volume(
- size=1,
- display_description=new_v_desc,
- availability_zone=volume['availability_zone'])
- self.assertEqual(200, resp.status)
+ params = {self.descrip_field: new_v_desc,
+ 'availability_zone': volume['availability_zone']}
+ resp, new_volume = self.client.create_volume(size=1, **params)
+ self.assertEqual(self.create_resp, resp.status)
self.assertIn('id', new_volume)
self.addCleanup(self._delete_volume, new_volume['id'])
self.client.wait_for_volume_status(new_volume['id'], 'available')
- resp, update_volume = \
- self.client.update_volume(
- new_volume['id'],
- display_name=volume['display_name'],
- display_description=volume['display_description'])
+
+ params = {self.name_field: volume[self.name_field],
+ self.descrip_field: volume[self.descrip_field]}
+ resp, update_volume = self.client.update_volume(new_volume['id'],
+ **params)
self.assertEqual(200, resp.status)
# NOTE(jdg): Revert back to strict true/false checking
@@ -159,5 +158,13 @@
self._volume_create_get_update_delete(source_volid=origin['id'])
-class VolumesGetTestXML(VolumesGetTest):
+class VolumesV2GetTestXML(VolumesV2GetTest):
+ _interface = "xml"
+
+
+class VolumesV1GetTest(VolumesV2GetTest):
+ _api_version = 1
+
+
+class VolumesV1GetTestXML(VolumesV1GetTest):
_interface = "xml"
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index bc5b1dc..8bd4c88 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -21,15 +21,16 @@
from tempest import test
-class VolumesNegativeTest(base.BaseVolumeV1Test):
- _interface = 'json'
+class VolumesV2NegativeTest(base.BaseVolumeTest):
@classmethod
@test.safe_setup
def setUpClass(cls):
- super(VolumesNegativeTest, cls).setUpClass()
+ super(VolumesV2NegativeTest, cls).setUpClass()
cls.client = cls.volumes_client
+ cls.name_field = cls.special_fields['name_field']
+
# Create a test shared instance and volume for attach/detach tests
cls.volume = cls.create_volume()
cls.mountpoint = "/dev/vdc"
@@ -237,7 +238,7 @@
@test.attr(type=['negative', 'gate'])
def test_list_volumes_with_nonexistent_name(self):
v_name = data_utils.rand_name('Volume-')
- params = {'display_name': v_name}
+ params = {self.name_field: v_name}
resp, fetched_volume = self.client.list_volumes(params)
self.assertEqual(200, resp.status)
self.assertEqual(0, len(fetched_volume))
@@ -245,7 +246,7 @@
@test.attr(type=['negative', 'gate'])
def test_list_volumes_detail_with_nonexistent_name(self):
v_name = data_utils.rand_name('Volume-')
- params = {'display_name': v_name}
+ params = {self.name_field: v_name}
resp, fetched_volume = self.client.list_volumes_with_detail(params)
self.assertEqual(200, resp.status)
self.assertEqual(0, len(fetched_volume))
@@ -265,5 +266,14 @@
self.assertEqual(0, len(fetched_volume))
-class VolumesNegativeTestXML(VolumesNegativeTest):
+class VolumesV2NegativeTestXML(VolumesV2NegativeTest):
+ _interface = 'xml'
+
+
+class VolumesV1NegativeTest(VolumesV2NegativeTest):
+ _api_version = 1
+ _name = 'display_name'
+
+
+class VolumesV1NegativeTestXML(VolumesV1NegativeTest):
_interface = 'xml'
diff --git a/tempest/api_schema/compute/v2/servers.py b/tempest/api_schema/compute/v2/servers.py
index 95c5760..551924a 100644
--- a/tempest/api_schema/compute/v2/servers.py
+++ b/tempest/api_schema/compute/v2/servers.py
@@ -270,3 +270,14 @@
# without these attributes. So they are not 'required'.
list_servers_detail['response_body']['properties']['servers']['items'][
'required'].append('hostId')
+
+rebuild_server = copy.deepcopy(update_server)
+rebuild_server['status_code'] = [202]
+del rebuild_server['response_body']['properties']['server'][
+ 'properties']['OS-DCF:diskConfig']
+
+rebuild_server_with_admin_pass = copy.deepcopy(rebuild_server)
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+ 'properties'].update({'adminPass': {'type': 'string'}})
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+ 'required'].append('adminPass')
diff --git a/tempest/api_schema/compute/v3/servers.py b/tempest/api_schema/compute/v3/servers.py
index dc800cd..cebb2d7 100644
--- a/tempest/api_schema/compute/v3/servers.py
+++ b/tempest/api_schema/compute/v3/servers.py
@@ -181,3 +181,12 @@
# attributes. So they are not 'required'.
list_servers_detail['response_body']['properties']['servers']['items'][
'required'].append('host_id')
+
+rebuild_server = copy.deepcopy(update_server)
+rebuild_server['status_code'] = [202]
+
+rebuild_server_with_admin_pass = copy.deepcopy(rebuild_server)
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+ 'properties'].update({'admin_password': {'type': 'string'}})
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+ 'required'].append('admin_password')
diff --git a/tempest/auth.py b/tempest/auth.py
index 830dca9..6dad3a4 100644
--- a/tempest/auth.py
+++ b/tempest/auth.py
@@ -13,10 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+import abc
import copy
import datetime
import exceptions
import re
+import six
import urlparse
from tempest import config
@@ -31,6 +33,7 @@
LOG = logging.getLogger(__name__)
+@six.add_metaclass(abc.ABCMeta)
class AuthProvider(object):
"""
Provide authentication
@@ -70,18 +73,21 @@
interface=self.interface, cache=self.cache
)
+ @abc.abstractmethod
def _decorate_request(self, filters, method, url, headers=None, body=None,
auth_data=None):
"""
Decorate request with authentication data
"""
- raise NotImplementedError
+ return
+ @abc.abstractmethod
def _get_auth(self):
- raise NotImplementedError
+ return
+ @abc.abstractmethod
def _fill_credentials(self, auth_data_body):
- raise NotImplementedError
+ return
def fill_credentials(self):
"""
@@ -130,8 +136,9 @@
self.cache = None
self.credentials.reset()
+ @abc.abstractmethod
def is_expired(self, auth_data):
- raise NotImplementedError
+ return
def auth_request(self, method, url, headers=None, body=None, filters=None):
"""
@@ -188,11 +195,12 @@
self.alt_part = request_part
self.alt_auth_data = auth_data
+ @abc.abstractmethod
def base_url(self, filters, auth_data=None):
"""
Extracts the base_url based on provided filters
"""
- raise NotImplementedError
+ return
class KeystoneAuthProvider(AuthProvider):
@@ -225,11 +233,13 @@
# no change to method or body
return str(_url), _headers, body
+ @abc.abstractmethod
def _auth_client(self):
- raise NotImplementedError
+ return
+ @abc.abstractmethod
def _auth_params(self):
- raise NotImplementedError
+ return
def _get_auth(self):
# Bypasses the cache
diff --git a/tempest/cli/README.rst b/tempest/cli/README.rst
index dcd940b..bc18084 100644
--- a/tempest/cli/README.rst
+++ b/tempest/cli/README.rst
@@ -1,3 +1,5 @@
+.. _cli_field_guide:
+
Tempest Field Guide to CLI tests
================================
diff --git a/tempest/config.py b/tempest/config.py
index c83f500..01bc243 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -268,12 +268,14 @@
default=['all'],
help='A list of enabled compute extensions with a special '
'entry all which indicates every extension is enabled. '
- 'Each extension should be specified with alias name'),
+ 'Each extension should be specified with alias name. '
+ 'Empty list indicates all extensions are disabled'),
cfg.ListOpt('api_v3_extensions',
default=['all'],
help='A list of enabled v3 extensions with a special entry all'
' which indicates every extension is enabled. '
- 'Each extension should be specified with alias name'),
+ 'Each extension should be specified with alias name. '
+ 'Empty list indicates all extensions are disabled'),
cfg.BoolOpt('change_password',
default=False,
help="Does the test environment support changing the admin "
@@ -314,7 +316,12 @@
cfg.BoolOpt('rescue',
default=True,
help='Does the test environment support instance rescue '
- 'mode?')
+ 'mode?'),
+ cfg.BoolOpt('enable_instance_password',
+ default=True,
+ help='Enables returning of the instance password by the '
+ 'relevant server API calls such as create, rebuild '
+ 'or rescue.')
]
@@ -441,7 +448,8 @@
cfg.ListOpt('api_extensions',
default=['all'],
help='A list of enabled network extensions with a special '
- 'entry all which indicates every extension is enabled'),
+ 'entry all which indicates every extension is enabled. '
+ 'Empty list indicates all extensions are disabled'),
cfg.BoolOpt('ipv6_subnet_attributes',
default=False,
help="Allow the execution of IPv6 subnet tests that use "
@@ -546,7 +554,8 @@
cfg.ListOpt('api_extensions',
default=['all'],
help='A list of enabled volume extensions with a special '
- 'entry all which indicates every extension is enabled'),
+ 'entry all which indicates every extension is enabled. '
+ 'Empty list indicates all extensions are disabled'),
cfg.BoolOpt('api_v1',
default=True,
help="Is the v1 volume API enabled"),
diff --git a/tempest/scenario/README.rst b/tempest/scenario/README.rst
index 835ba99..5a287d6 100644
--- a/tempest/scenario/README.rst
+++ b/tempest/scenario/README.rst
@@ -1,3 +1,5 @@
+.. _scenario_field_guide:
+
Tempest Field Guide to Scenario tests
=====================================
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index aa24c31..3cfc698 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -113,6 +113,11 @@
cls.ceilometer_client = cls.manager.ceilometer_client
@classmethod
+ def tearDownClass(cls):
+ cls.isolated_creds.clear_isolated_creds()
+ super(OfficialClientTest, cls).tearDownClass()
+
+ @classmethod
def _get_credentials(cls, get_creds, ctype):
if CONF.compute.allow_tenant_isolation:
creds = get_creds()
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 80bb711..05f74cd 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -269,7 +269,12 @@
if 'disk_config' in kwargs:
kwargs['OS-DCF:diskConfig'] = kwargs['disk_config']
del kwargs['disk_config']
- return self.action(server_id, 'rebuild', 'server', None, **kwargs)
+ if CONF.compute_feature_enabled.enable_instance_password:
+ rebuild_schema = schema.rebuild_server_with_admin_pass
+ else:
+ rebuild_schema = schema.rebuild_server
+ return self.action(server_id, 'rebuild', 'server',
+ rebuild_schema, **kwargs)
def resize(self, server_id, flavor_ref, **kwargs):
"""Changes the flavor of a server."""
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index a5b31d3..27e95e8 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -272,7 +272,12 @@
if 'disk_config' in kwargs:
kwargs['os-disk-config:disk_config'] = kwargs['disk_config']
del kwargs['disk_config']
- return self.action(server_id, 'rebuild', 'server', None, **kwargs)
+ if CONF.compute_feature_enabled.enable_instance_password:
+ rebuild_schema = schema.rebuild_server_with_admin_pass
+ else:
+ rebuild_schema = schema.rebuild_server
+ return self.action(server_id, 'rebuild', 'server',
+ rebuild_schema, **kwargs)
def resize(self, server_id, flavor_ref, **kwargs):
"""Changes the flavor of a server."""
diff --git a/tempest/stress/README.rst b/tempest/stress/README.rst
index 0a63679..4f1f56c 100644
--- a/tempest/stress/README.rst
+++ b/tempest/stress/README.rst
@@ -1,3 +1,5 @@
+.. _stress_field_guide:
+
Tempest Field Guide to Stress Tests
===================================
diff --git a/tempest/test.py b/tempest/test.py
index afe7a96..5b7330b 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -215,6 +215,8 @@
'network': CONF.network_feature_enabled.api_extensions,
'object': CONF.object_storage_feature_enabled.discoverable_apis,
}
+ if len(config_dict[service]) == 0:
+ return False
if config_dict[service][0] == 'all':
return True
if extension_name in config_dict[service]:
diff --git a/tempest/tests/README.rst b/tempest/tests/README.rst
index 33d321f..e54d4c0 100644
--- a/tempest/tests/README.rst
+++ b/tempest/tests/README.rst
@@ -1,3 +1,5 @@
+.. _unit_tests_field_guide:
+
Tempest Field Guide to Unit tests
=================================
diff --git a/tempest/tests/test_auth.py b/tempest/tests/test_auth.py
index 1dcddad..6a2e335 100644
--- a/tempest/tests/test_auth.py
+++ b/tempest/tests/test_auth.py
@@ -59,12 +59,24 @@
obviously don't test not implemented method or the ones which strongly
depends on them.
"""
- _auth_provider_class = auth.AuthProvider
- def test_check_credentials_class(self):
- self.assertRaises(NotImplementedError,
- self.auth_provider.check_credentials,
- auth.Credentials())
+ class FakeAuthProviderImpl(auth.AuthProvider):
+ def _decorate_request():
+ pass
+
+ def _fill_credentials():
+ pass
+
+ def _get_auth():
+ pass
+
+ def base_url():
+ pass
+
+ def is_expired():
+ pass
+
+ _auth_provider_class = FakeAuthProviderImpl
def test_check_credentials_bad_type(self):
self.assertFalse(self.auth_provider.check_credentials([]))
@@ -74,16 +86,6 @@
auth_provider = self._auth(credentials={})
self.assertIsInstance(auth_provider.credentials, auth.Credentials)
- def test_instantiate_with_bad_credentials_type(self):
- """
- Assure that credentials with bad type fail with TypeError
- """
- self.assertRaises(TypeError, self._auth, [])
-
- def test_auth_data_property(self):
- self.assertRaises(NotImplementedError, getattr, self.auth_provider,
- 'auth_data')
-
def test_auth_data_property_when_cache_exists(self):
self.auth_provider.cache = 'foo'
self.useFixture(mockpatch.PatchObject(self.auth_provider,
@@ -110,9 +112,10 @@
self.assertIsNone(self.auth_provider.alt_part)
self.assertIsNone(self.auth_provider.alt_auth_data)
- def test_fill_credentials(self):
- self.assertRaises(NotImplementedError,
- self.auth_provider.fill_credentials)
+ def test_auth_class(self):
+ self.assertRaises(TypeError,
+ auth.AuthProvider,
+ fake_credentials.FakeCredentials)
class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp):
diff --git a/tempest/thirdparty/README.rst b/tempest/thirdparty/README.rst
index 53cb54b..b0bfdf7 100644
--- a/tempest/thirdparty/README.rst
+++ b/tempest/thirdparty/README.rst
@@ -1,3 +1,5 @@
+.. _third_party_field_guide:
+
Tempest Field Guide to Third Party API tests
============================================