Merge "Correct misspelled words"
diff --git a/doc/source/index.rst b/doc/source/index.rst
index c45273e..25bc900 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -1,8 +1,3 @@
-.. Tempest documentation master file, created by
- sphinx-quickstart on Tue May 21 17:43:32 2013.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
=======================
Tempest Testing Project
=======================
diff --git a/tempest/README.rst b/tempest/README.rst
index dbac809..18c7cf3 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -62,13 +62,10 @@
stress
------
-Stress tests are designed to stress an OpenStack environment by
-running a high workload against it and seeing what breaks. Tools may
-be provided to help detect breaks (stack traces in the logs).
-
-TODO: old stress tests deleted, new_stress that david is working on
-moves into here.
-
+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
----------
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 9555367..3a6de36 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -26,7 +26,7 @@
@classmethod
def setUpClass(cls):
super(AZAdminV3Test, cls).setUpClass()
- cls.client = cls.os_adm.availability_zone_client
+ cls.client = cls.availability_zone_admin_client
@test.attr(type='gate')
def test_get_availability_zone_list(self):
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 48f9ffb..85b26a1 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -86,8 +86,27 @@
# Verify that GET shows the specified hypervisor uptime
hypers = self._list_hypervisors()
- has_valid_uptime = False
+ # Ironic will register each baremetal node as a 'hypervisor',
+ # so the hypervisor list can contain many hypervisors of type
+ # 'ironic'. If they are ALL ironic, skip this test since ironic
+ # doesn't support hypervisor uptime. Otherwise, remove them
+ # from the list of hypervisors to test.
+ ironic_only = True
+ hypers_without_ironic = []
for hyper in hypers:
+ resp, details = (self.client.
+ get_hypervisor_show_details(hypers[0]['id']))
+ self.assertEqual(200, resp.status)
+ if details['hypervisor_type'] != 'ironic':
+ hypers_without_ironic.append(hyper)
+ ironic_only = False
+
+ if ironic_only:
+ raise self.skipException(
+ "Ironic does not support hypervisor uptime")
+
+ has_valid_uptime = False
+ for hyper in hypers_without_ironic:
# because hypervisors might be disabled, this loops looking
# for any good hit.
try:
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index caf4174..70a9604 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -392,8 +392,11 @@
msg = ("Missing Compute Admin API credentials "
"in configuration.")
raise cls.skipException(msg)
+ if cls._api_version == 2:
+ cls.availability_zone_admin_client = (
+ cls.os_adm.availability_zone_client)
- if cls._api_version == 3:
+ else:
cls.servers_admin_client = cls.os_adm.servers_v3_client
cls.services_admin_client = cls.os_adm.services_v3_client
cls.availability_zone_admin_client = \
diff --git a/tempest/api/compute/v3/admin/test_hypervisor.py b/tempest/api/compute/v3/admin/test_hypervisor.py
index f3397a8..9a23789 100644
--- a/tempest/api/compute/v3/admin/test_hypervisor.py
+++ b/tempest/api/compute/v3/admin/test_hypervisor.py
@@ -83,7 +83,27 @@
# Verify that GET shows the specified hypervisor uptime
hypers = self._list_hypervisors()
- resp, uptime = self.client.get_hypervisor_uptime(hypers[0]['id'])
+ # Ironic will register each baremetal node as a 'hypervisor',
+ # so the hypervisor list can contain many hypervisors of type
+ # 'ironic'. If they are ALL ironic, skip this test since ironic
+ # doesn't support hypervisor uptime. Otherwise, remove them
+ # from the list of hypervisors to test.
+ ironic_only = True
+ hypers_without_ironic = []
+ for hyper in hypers:
+ resp, details = (self.client.
+ get_hypervisor_show_details(hypers[0]['id']))
+ self.assertEqual(200, resp.status)
+ if details['hypervisor_type'] != 'ironic':
+ hypers_without_ironic.append(hyper)
+ ironic_only = False
+
+ if ironic_only:
+ raise self.skipException(
+ "Ironic does not support hypervisor uptime")
+
+ resp, uptime = self.client.get_hypervisor_uptime(
+ hypers_without_ironic[0]['id'])
self.assertEqual(200, resp.status)
self.assertTrue(len(uptime) > 0)
diff --git a/tempest/api_schema/compute/servers.py b/tempest/api_schema/compute/servers.py
index ad0aa29..6b27f3d 100644
--- a/tempest/api_schema/compute/servers.py
+++ b/tempest/api_schema/compute/servers.py
@@ -48,50 +48,52 @@
}
}
+common_show_server = {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'name': {'type': 'string'},
+ 'status': {'type': 'string'},
+ 'image': {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'links': parameter_types.links
+ },
+ 'required': ['id', 'links']
+ },
+ 'flavor': {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'links': parameter_types.links
+ },
+ 'required': ['id', 'links']
+ },
+ 'user_id': {'type': 'string'},
+ 'tenant_id': {'type': 'string'},
+ 'created': {'type': 'string'},
+ 'updated': {'type': 'string'},
+ 'progress': {'type': 'integer'},
+ 'metadata': {'type': 'object'},
+ 'links': parameter_types.links,
+ 'addresses': parameter_types.addresses,
+ },
+ # NOTE(GMann): 'progress' attribute is present in the response
+ # only when server's status is one of the progress statuses
+ # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE")
+ # So it is not defined as 'required'.
+ 'required': ['id', 'name', 'status', 'image', 'flavor',
+ 'user_id', 'tenant_id', 'created', 'updated',
+ 'metadata', 'links', 'addresses']
+}
+
base_update_get_server = {
'status_code': [200],
'response_body': {
'type': 'object',
'properties': {
- 'server': {
- 'type': 'object',
- 'properties': {
- 'id': {'type': 'string'},
- 'name': {'type': 'string'},
- 'status': {'type': 'string'},
- 'image': {
- 'type': 'object',
- 'properties': {
- 'id': {'type': 'string'},
- 'links': parameter_types.links
- },
- 'required': ['id', 'links']
- },
- 'flavor': {
- 'type': 'object',
- 'properties': {
- 'id': {'type': 'string'},
- 'links': parameter_types.links
- },
- 'required': ['id', 'links']
- },
- 'user_id': {'type': 'string'},
- 'tenant_id': {'type': 'string'},
- 'created': {'type': 'string'},
- 'updated': {'type': 'string'},
- 'progress': {'type': 'integer'},
- 'metadata': {'type': 'object'},
- 'links': parameter_types.links,
- 'addresses': parameter_types.addresses,
- },
- # NOTE(GMann): 'progress' attribute is present in the response
- # only when server's status is one of the progress statuses
- # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE")
- # So it is not defined as 'required'.
- 'required': ['id', 'name', 'status', 'image', 'flavor',
- 'user_id', 'tenant_id', 'created', 'updated',
- 'metadata', 'links', 'addresses']
- }
+ 'server': common_show_server
},
'required': ['server']
}
@@ -179,3 +181,17 @@
'required': ['action', 'request_id', 'user_id', 'project_id',
'start_time', 'message']
}
+
+base_list_servers_detail = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'servers': {
+ 'type': 'array',
+ 'items': common_show_server
+ }
+ },
+ 'required': ['servers']
+ }
+}
diff --git a/tempest/api_schema/compute/v2/servers.py b/tempest/api_schema/compute/v2/servers.py
index dc4054c..cd46f9b 100644
--- a/tempest/api_schema/compute/v2/servers.py
+++ b/tempest/api_schema/compute/v2/servers.py
@@ -240,3 +240,17 @@
'required': ['instanceActions']
}
}
+
+list_servers_detail = copy.deepcopy(servers.base_list_servers_detail)
+list_servers_detail['response_body']['properties']['servers']['items'][
+ 'properties'].update({
+ 'hostId': {'type': 'string'},
+ 'OS-DCF:diskConfig': {'type': 'string'},
+ 'accessIPv4': parameter_types.access_ip_v4,
+ 'accessIPv6': parameter_types.access_ip_v6
+ })
+# NOTE(GMann): OS-DCF:diskConfig and accessIPv4/v6 are API
+# extensions, and some environments return a response
+# without these attributes. So they are not 'required'.
+list_servers_detail['response_body']['properties']['servers']['items'][
+ 'required'].append('hostId')
diff --git a/tempest/api_schema/compute/v3/servers.py b/tempest/api_schema/compute/v3/servers.py
index 3b50516..b6cb13b 100644
--- a/tempest/api_schema/compute/v3/servers.py
+++ b/tempest/api_schema/compute/v3/servers.py
@@ -151,3 +151,17 @@
'required': ['server_actions']
}
}
+
+list_servers_detail = copy.deepcopy(servers.base_list_servers_detail)
+list_servers_detail['response_body']['properties']['servers']['items'][
+ 'properties'].update({
+ 'addresses': addresses_v3,
+ 'host_id': {'type': 'string'},
+ 'os-access-ips:access_ip_v4': parameter_types.access_ip_v4,
+ 'os-access-ips:access_ip_v6': parameter_types.access_ip_v6
+ })
+# NOTE(GMann): os-access-ips:access_ip_v4/v6 are API extension,
+# and some environments return a response without these
+# attributes. So they are not 'required'.
+list_servers_detail['response_body']['properties']['servers']['items'][
+ 'required'].append('host_id')
diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py
index 0571f4f..ba94c82 100644
--- a/tempest/cli/__init__.py
+++ b/tempest/cli/__init__.py
@@ -95,14 +95,15 @@
return self.cmd_with_auth(
'neutron', action, flags, params, admin, fail_ok)
- def sahara(self, action, flags='', params='', admin=True, fail_ok=False):
+ def sahara(self, action, flags='', params='', admin=True,
+ fail_ok=False, merge_stderr=True):
"""Executes sahara command for the given action."""
flags += ' --endpoint-type %s' % CONF.data_processing.endpoint_type
return self.cmd_with_auth(
- 'sahara', action, flags, params, admin, fail_ok)
+ 'sahara', action, flags, params, admin, fail_ok, merge_stderr)
def cmd_with_auth(self, cmd, action, flags='', params='',
- admin=True, fail_ok=False):
+ admin=True, fail_ok=False, merge_stderr=False):
"""Executes given command with auth attributes appended."""
# TODO(jogo) make admin=False work
creds = ('--os-username %s --os-tenant-name %s --os-password %s '
@@ -112,7 +113,7 @@
CONF.identity.admin_password,
CONF.identity.uri))
flags = creds + ' ' + flags
- return self.cmd(cmd, action, flags, params, fail_ok)
+ return self.cmd(cmd, action, flags, params, fail_ok, merge_stderr)
def cmd(self, cmd, action, flags='', params='', fail_ok=False,
merge_stderr=False):
@@ -120,7 +121,7 @@
cmd = ' '.join([os.path.join(CONF.cli.cli_dir, cmd),
flags, action, params])
LOG.info("running: '%s'" % cmd)
- cmd = shlex.split(cmd)
+ cmd = shlex.split(cmd.encode('utf-8'))
result = ''
result_err = ''
stdout = subprocess.PIPE
diff --git a/tempest/cli/simple_read_only/test_sahara.py b/tempest/cli/simple_read_only/test_sahara.py
index 36cc324..f00dcae 100644
--- a/tempest/cli/simple_read_only/test_sahara.py
+++ b/tempest/cli/simple_read_only/test_sahara.py
@@ -12,8 +12,8 @@
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-
import logging
+import re
import subprocess
from tempest import cli
@@ -138,3 +138,30 @@
'cluster_id',
'status'
])
+
+ def test_sahara_bash_completion(self):
+ self.sahara('bash-completion')
+
+ # Optional arguments
+ def test_sahara_help(self):
+ help_text = self.sahara('help')
+ lines = help_text.split('\n')
+ self.assertFirstLineStartsWith(lines, 'usage: sahara')
+
+ commands = []
+ cmds_start = lines.index('Positional arguments:')
+ cmds_end = lines.index('Optional arguments:')
+ command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)')
+ for line in lines[cmds_start:cmds_end]:
+ match = command_pattern.match(line)
+ if match:
+ commands.append(match.group(1))
+ commands = set(commands)
+ wanted_commands = set(('cluster-create', 'data-source-create',
+ 'image-unregister', 'job-binary-create',
+ 'plugin-list', 'job-binary-create', 'help'))
+ self.assertFalse(wanted_commands - commands)
+
+ def test_sahara_version(self):
+ version = self.sahara('', flags='--version')
+ self.assertTrue(re.search('[0-9.]+', version))
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 19e816b..0b72b1c 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -169,7 +169,7 @@
def collect_users(users):
global USERS
- LOG.info("Creating users")
+ LOG.info("Collecting users")
admin = keystone_admin()
for u in users:
tenant = admin.identity.get_tenant_by_name(u['tenant'])
@@ -202,6 +202,7 @@
We don't use the resource list for this because we need to validate
that things like tenantId didn't drift across versions.
"""
+ LOG.info("checking users")
for name, user in self.users.iteritems():
client = keystone_admin()
_, found = client.identity.get_user(user['id'])
@@ -217,6 +218,7 @@
def check_objects(self):
"""Check that the objects created are still there."""
+ LOG.info("checking objects")
for obj in self.res['objects']:
client = client_for_user(obj['owner'])
r, contents = client.objects.get_object(
@@ -226,6 +228,7 @@
def check_servers(self):
"""Check that the servers are still up and running."""
+ LOG.info("checking servers")
for server in self.res['servers']:
client = client_for_user(server['owner'])
found = _get_server_by_name(client, server['name'])
@@ -242,6 +245,7 @@
def check_volumes(self):
"""Check that the volumes are still there and attached."""
+ LOG.info("checking volumes")
for volume in self.res['volumes']:
client = client_for_user(volume['owner'])
found = _get_volume_by_name(client, volume['name'])
diff --git a/tempest/common/commands.py b/tempest/common/commands.py
index 2ab008d..6583475 100644
--- a/tempest/common/commands.py
+++ b/tempest/common/commands.py
@@ -25,7 +25,7 @@
def sudo_cmd_call(cmd):
- args = shlex.split(cmd)
+ args = shlex.split(cmd.encode('utf-8'))
subprocess_args = {'stdout': subprocess.PIPE,
'stderr': subprocess.STDOUT}
proc = subprocess.Popen(['/usr/bin/sudo', '-n'] + args,
@@ -84,7 +84,7 @@
"-i %(pkey)s %(file1)s %(dest)s" % {'pkey': pkey,
'file1': file_from,
'dest': dest}
- args = shlex.split(cmd)
+ args = shlex.split(cmd.encode('utf-8'))
subprocess_args = {'stdout': subprocess.PIPE,
'stderr': subprocess.STDOUT}
proc = subprocess.Popen(args, **subprocess_args)
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 69d2f35..fea0d28 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -164,6 +164,7 @@
resp, body = self.get(url)
body = json.loads(body)
+ self.validate_response(schema.list_servers_detail, resp, body)
return resp, body
def wait_for_server_status(self, server_id, status, extra_timeout=0,
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index d933998..932cc2c 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -166,6 +166,7 @@
resp, body = self.get(url)
body = json.loads(body)
+ self.validate_response(schema.list_servers_detail, resp, body)
return resp, body
def wait_for_server_status(self, server_id, status, extra_timeout=0,
diff --git a/tempest/tests/stress/test_stress.py b/tempest/tests/stress/test_stress.py
index 5a334c5..3dc2199 100644
--- a/tempest/tests/stress/test_stress.py
+++ b/tempest/tests/stress/test_stress.py
@@ -32,7 +32,7 @@
cmd = ' '.join([cmd, param])
LOG.info("running: '%s'" % cmd)
cmd_str = cmd
- cmd = shlex.split(cmd)
+ cmd = shlex.split(cmd.encode('utf-8'))
result = ''
result_err = ''
try:
diff --git a/tempest/tests/test_waiters.py b/tempest/tests/test_waiters.py
index 1f9825e..a29cb46 100644
--- a/tempest/tests/test_waiters.py
+++ b/tempest/tests/test_waiters.py
@@ -15,6 +15,7 @@
import time
import mock
+import testtools
from tempest.common import waiters
from tempest import exceptions
@@ -47,3 +48,221 @@
self.assertRaises(exceptions.AddImageException,
waiters.wait_for_image_status,
self.client, 'fake_image_id', 'active')
+
+
+class TestServerWaiters(base.TestCase):
+ def setUp(self):
+ super(TestServerWaiters, self).setUp()
+ self.client = mock.MagicMock()
+ self.client.build_timeout = 1
+ self.client.build_interval = 1
+
+ def test_wait_for_server_status(self):
+ self.client.get_server.return_value = (None, {'status':
+ 'active'}
+ )
+ start_time = int(time.time())
+ waiters.wait_for_server_status(self.client, 'fake_svr_id',
+ 'active'
+ )
+ end_time = int(time.time())
+ # Ensure waiter returns before build_timeout
+ self.assertTrue((end_time - start_time) < 2)
+
+ def test_wait_for_server_status_BUILD_from_not_UNKNOWN(self):
+ self.client.get_server.return_value = (None, {'status': 'active'})
+ start_time = int(time.time())
+ waiters.wait_for_server_status(self.client, 'fake_svr_id',
+ 'BUILD')
+ end_time = int(time.time())
+ # Ensure waiter returns before build_timeout
+ self.assertTrue((end_time - start_time) < 2)
+
+ def test_wait_for_server_status_ready_wait_with_BUILD(self):
+ self.client.get_server.return_value = (None, {'status': 'BUILD'})
+ start_time = int(time.time())
+ waiters.wait_for_server_status(self.client, 'fake_svr_id',
+ 'BUILD', True)
+ end_time = int(time.time())
+ # Ensure waiter returns before build_timeout
+ self.assertTrue((end_time - start_time) < 2)
+
+ def test_wait_for_server_status_ready_wait(self):
+ self.client.get_server.return_value = (None, {'status':
+ 'ERROR',
+ 'OS-EXT-STS:task_state':
+ 'n/a'
+ }
+ )
+ self.client.get_console_output.return_value = (None,
+ {'output': 'Server fake_svr_id failed to reach '
+ 'active status and task state n/a within the '
+ 'required time (1 s).\nCurrent status: SUSPENDED.'
+ '\nCurrent task state: None.'}
+ )
+ self.assertRaises(exceptions.BuildErrorException,
+ waiters.wait_for_server_status,
+ self.client, 'fake_svr_id', 'active',
+ ready_wait=True, extra_timeout=0,
+ raise_on_error=True
+ )
+
+ def test_wait_for_server_status_no_ready_wait(self):
+ self.client.get_server.return_value = (None, {'status':
+ 'ERROR',
+ 'OS-EXT-STS:task_state':
+ 'n/a'
+ }
+ )
+ start_time = int(time.time())
+ waiters.wait_for_server_status(self.client, 'fake_svr_id',
+ 'ERROR', ready_wait=False,
+ extra_timeout=10, raise_on_error=True
+ )
+ end_time = int(time.time())
+ # Ensure waiter returns before build_timeout + extra_timeout
+ self.assertTrue((end_time - start_time) < 12)
+
+ def test_wait_for_server_status_timeout(self):
+ self.client.get_server.return_value = (None, {'status': 'SUSPENDED'})
+ self.client.get_console_output.return_value = (None,
+ {'output': 'Server fake_svr_id failed to reach '
+ 'active status and task state n/a within the '
+ 'required time (1 s).\nCurrent status: SUSPENDED.'
+ '\nCurrent task state: None.'}
+ )
+ self.assertRaises(exceptions.TimeoutException,
+ waiters.wait_for_server_status,
+ self.client, 'fake_svr_id', 'active')
+
+ def test_wait_for_server_status_extra_timeout(self):
+ self.client.get_server.return_value = (None, {'status': 'SUSPENDED'})
+ start_time = int(time.time())
+ self.client.get_console_output.return_value = (None,
+ {'output': 'Server fake_svr_id failed to reach '
+ 'active status and task state n/a within the '
+ 'required time (10 s). \nCurrent status: SUSPENDED.'
+ '\nCurrent task state: None.'}
+ )
+ self.assertRaises(exceptions.TimeoutException,
+ waiters.wait_for_server_status,
+ self.client, 'fake_svr_id',
+ 'active', ready_wait=True,
+ extra_timeout=10, raise_on_error=True
+ )
+ end_time = int(time.time())
+ # Ensure waiter returns after build_timeout but
+ # before build_timeout+extra timeout
+ self.assertTrue(10 < (end_time - start_time) < 12)
+
+ def test_wait_for_server_status_error_on_server_create(self):
+ self.client.get_server.return_value = (None, {'status': 'ERROR'})
+ self.client.get_console_output.return_value = (None,
+ {'output': 'Server fake_svr_id failed to reach '
+ 'activestatus and task state n/a within the '
+ 'required time (1 s).\nCurrent status: ERROR.'
+ '\nCurrent task state: None.'}
+ )
+ self.assertRaises(exceptions.BuildErrorException,
+ waiters.wait_for_server_status,
+ self.client, 'fake_svr_id', 'active')
+
+ def test_wait_for_server_status_no_raise_on_error(self):
+ self.client.get_server.return_value = (None, {'status': 'ERROR'})
+ self.client.get_console_output.return_value = (None,
+ {'output': 'Server fake_svr_id failed to reach '
+ 'activestatus and task state n/a within the '
+ 'required time (1 s).\nCurrent status: ERROR.'
+ '\nCurrent task state: None.'}
+ )
+ self.assertRaises(exceptions.TimeoutException,
+ waiters.wait_for_server_status,
+ self.client, 'fake_svr_id', 'active',
+ ready_wait=True, extra_timeout=0,
+ raise_on_error=False
+ )
+
+ def test_wait_for_server_status_no_ready_wait_timeout(self):
+ self.client.get_server.return_value = (None, {'status': 'ERROR'})
+ self.client.get_console_output.return_value = (None,
+ {'output': 'Server fake_svr_id failed to reach '
+ 'active status and task state n/a within the '
+ 'required time (11 s).\nCurrent status: ERROR.'
+ '\nCurrent task state: None.'}
+ )
+ expected_msg = '''Request timed out
+Details: (TestServerWaiters:test_wait_for_server_status_no_ready_wait_timeout)\
+ Server fake_svr_id failed to reach active status and task state "n/a" within\
+ the required time (11 s). Current status: ERROR. Current task state: None.\
+'''
+ with testtools.ExpectedException(exceptions.TimeoutException,
+ testtools.matchers.AfterPreprocessing(
+ str,
+ testtools.matchers.Equals(expected_msg)
+ )
+ ):
+ waiters.wait_for_server_status(self.client, 'fake_svr_id',
+ 'active', ready_wait=False,
+ extra_timeout=10,
+ raise_on_error=False
+ )
+
+ def test_wait_for_server_status_ready_wait_timeout(self):
+ self.client.get_server.return_value = (None, {'status': 'ERROR'})
+ self.client.get_console_output.return_value = (None,
+ {'output': 'Server fake_svr_id failed to reach '
+ 'activestatus and task state n/a within the '
+ 'required time (11 s).\nCurrent status: ERROR.'
+ '\nCurrent task state: None.'}
+ )
+ expected_msg = '''Request timed out
+Details: (TestServerWaiters:test_wait_for_server_status_ready_wait_timeout)\
+ Server fake_svr_id failed to reach active status and task state "None" within\
+ the required time (11 s). Current status: ERROR. Current task state: None.\
+'''
+ with testtools.ExpectedException(exceptions.TimeoutException,
+ testtools.matchers.AfterPreprocessing(
+ str,
+ testtools.matchers.Equals(expected_msg)
+ )
+ ):
+ waiters.wait_for_server_status(self.client, 'fake_svr_id',
+ 'active', ready_wait=True,
+ extra_timeout=10,
+ raise_on_error=False
+ )
+
+ def test_wait_for_changing_server_status(self):
+ self.client.get_server.side_effect = [(None, {'status': 'BUILD'}),
+ (None, {'status': 'active'})]
+ start_time = int(time.time())
+ waiters.wait_for_server_status(self.client, 'fake_svr_id',
+ 'active', ready_wait=True,
+ extra_timeout=10,
+ raise_on_error=True
+ )
+ end_time = int(time.time())
+ # Ensure waiter returns before build_timeout + extra_timeout
+ self.assertTrue((end_time - start_time) < 12)
+
+ def test_wait_for_changing_server_task_status(self):
+ self.client.get_server.side_effect = [(None, {'status': 'BUILD',
+ 'OS-EXT-STS:task_state':
+ 'n/a'
+ }
+ ),
+ (None, {'status': 'active',
+ 'OS-EXT-STS:task_state':
+ 'None'
+ }
+ )
+ ]
+ start_time = int(time.time())
+ waiters.wait_for_server_status(self.client, 'fake_svr_id',
+ 'active', ready_wait=True,
+ extra_timeout=10,
+ raise_on_error=True
+ )
+ end_time = int(time.time())
+ # Ensure waiter returns before build_timeout + extra_timeout
+ self.assertTrue((end_time - start_time) < 12)
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 7713931..2c68d6b 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -177,7 +177,10 @@
instance.remove_tag('key1', value='value1')
tags = self.ec2_client.get_all_tags()
- self.assertEqual(len(tags), 0, str(tags))
+
+ # NOTE: Volume-attach and detach causes metadata (tags) to be created
+ # for the volume. So exclude them while asserting.
+ self.assertNotIn('key1', tags)
for instance in reservation.instances:
instance.stop()
diff --git a/test-requirements.txt b/test-requirements.txt
index 13ef291..cd8154b 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,6 +1,5 @@
hacking>=0.9.2,<0.10
# needed for doc build
-docutils==0.9.1
sphinx>=1.1.2,!=1.2.0,<1.3
python-subunit>=0.0.18
oslosphinx