Add unit tests to increase coverage
This patch proposes adding several new unit tests in effort to increase
the total unit test coverage.
Additionally, the ./tempest/serial_tests/ directory is not included in
coverage calculation. The reason being we don't want to test tests with
unit tests, which becomes a bit of an overkill.
Finally, there is an addition of a new option for the coverage program
called --fail-under. It will result the program in failure if the
coverage is under set percentage. Reason for this implementation is to
encourage writing unit tests for new code.
Change-Id: I804116413cd7d73cd7e5ae71409a8855ef937b88
diff --git a/.coveragerc b/.coveragerc
index 449e62c..398755b 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,4 +1,4 @@
[run]
branch = True
source = tempest
-omit = tempest/tests/*,tempest/scenario/test_*.py,tempest/api/*
+omit = tempest/tests/*,tempest/scenario/test_*.py,tempest/api/*,tempest/serial_tests/*
diff --git a/tempest/tests/common/test_compute.py b/tempest/tests/common/test_compute.py
index 142bb08..4d933cd 100644
--- a/tempest/tests/common/test_compute.py
+++ b/tempest/tests/common/test_compute.py
@@ -17,8 +17,9 @@
from urllib import parse as urlparse
-
from tempest.common import compute
+from tempest import exceptions
+from tempest.lib import exceptions as lib_exc
from tempest.tests import base
@@ -28,6 +29,58 @@
self.client_sock = mock.Mock()
self.url = urlparse.urlparse("http://www.fake.com:80")
+ @mock.patch('tempest.common.compute.' 'config.CONF.validation')
+ def test_get_server_ip_connect_method_floating(self, mock_conf):
+ fake_server = {'id': 'fake-uuid'}
+ fake_vr = {'floating_ip': {'ip': '10.10.10.1'}}
+ mock_conf.connect_method = 'floating'
+
+ fake_server_ip = compute.get_server_ip(fake_server, fake_vr)
+ self.assertEqual(fake_server_ip, '10.10.10.1')
+
+ # assert that InvalidParam is raised when validadation
+ # resources are not set
+ self.assertRaises(lib_exc.InvalidParam,
+ compute.get_server_ip,
+ fake_server)
+
+ @mock.patch('tempest.common.compute.' 'config.CONF.validation')
+ def test_get_server_ip_connect_method_fixed(self, mock_conf):
+ fake_server = {'id': 'fake-uuid',
+ 'addresses': {
+ 'private': [
+ {'addr': '192.168.0.3',
+ 'version': 4}]}}
+ mock_conf.connect_method = 'fixed'
+ mock_conf.network_for_ssh = 'private'
+ mock_conf.ip_version_for_ssh = 4
+
+ fake_server_ip = compute.get_server_ip(fake_server)
+ self.assertEqual(fake_server_ip, '192.168.0.3')
+
+ fake_server_v6 = {'id': 'fake-uuid',
+ 'addresses': {
+ 'private': [
+ {'addr': '2345:0425:2CA1::0567:5673:23b5',
+ 'version': 6}]}}
+ # assert when server is unreachable
+ self.assertRaises(exceptions.ServerUnreachable,
+ compute.get_server_ip,
+ fake_server_v6)
+
+ @mock.patch('tempest.common.compute.' 'config.CONF.validation')
+ def test_get_server_ip_invalid_config(self, mock_conf):
+ fake_server = {'id': 'fake-uuid',
+ 'addresses': {
+ 'private': [
+ {'addr': '192.168.0.3',
+ 'version': 4}]}}
+ mock_conf.connect_method = 'fake-method'
+ # assert when the connection method is not correctly set
+ self.assertRaises(lib_exc.InvalidConfiguration,
+ compute.get_server_ip,
+ fake_server)
+
def test_rfp_frame_not_cached(self):
# rfp negotiation frame arrived separately after upgrade
# response, so it's not cached.
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index 93c949e..f194173 100755
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -27,6 +27,78 @@
import tempest.tests.utils as utils
+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):
+ fake_server = {'id': 'fake-uuid',
+ 'status': 'ACTIVE'}
+ self.client.show_server.return_value = ({'server': fake_server})
+ start_time = int(time.time())
+ waiters.wait_for_server_status(
+ self.client, fake_server['id'], 'ACTIVE')
+ end_time = int(time.time())
+ # Ensure waiter returns before build_timeout
+ self.assertLess((end_time - start_time), 10)
+
+ def test_wait_for_server_status_build(self):
+ fake_server = {'id': 'fake-uuid',
+ 'status': 'BUILD'}
+ self.client.show_server.return_value = ({'server': fake_server})
+ start_time = int(time.time())
+ waiters.wait_for_server_status(self.client, fake_server['id'], 'BUILD')
+ end_time = int(time.time())
+ # Ensure waiter returns before build_timeout
+ self.assertLess((end_time - start_time), 10)
+
+ def test_wait_for_server_status_timeout(self):
+ time_mock = self.patch('time.time')
+ time_mock.side_effect = utils.generate_timeout_series(1)
+
+ fake_server = {'id': 'fake-uuid',
+ 'status': 'SAVING'}
+ self.client.show_server.return_value = ({'server': fake_server})
+ self.assertRaises(lib_exc.TimeoutException,
+ waiters.wait_for_server_status,
+ self.client, fake_server['id'], 'ACTIVE')
+
+ def test_wait_for_server_status_error_on_server_build(self):
+ fake_server = {'id': 'fake-uuid',
+ 'status': 'ERROR'}
+ self.client.show_server.return_value = ({'server': fake_server})
+ self.assertRaises(exceptions.BuildErrorException,
+ waiters.wait_for_server_status,
+ self.client, fake_server['id'], 'ACTIVE')
+
+ def test_wait_for_server_termination(self):
+ fake_server = {'id': 'fake-uuid',
+ 'status': 'ACTIVE'}
+ self.client.show_server.side_effect = lib_exc.NotFound
+ waiters.wait_for_server_termination(self.client, fake_server['id'])
+
+ def test_wait_for_server_termination_timeout(self):
+ time_mock = self.patch('time.time')
+ time_mock.side_effect = utils.generate_timeout_series(1)
+
+ fake_server = {'id': 'fake-uuid',
+ 'status': 'ACTIVE'}
+ self.assertRaises(lib_exc.TimeoutException,
+ waiters.wait_for_server_termination,
+ self.client, fake_server['id'])
+
+ def test_wait_for_server_termination_error_status(self):
+ fake_server = {'id': 'fake-uuid',
+ 'status': 'ERROR'}
+ self.client.show_server.return_value = ({'server': fake_server})
+ self.assertRaises(lib_exc.DeleteErrorException,
+ waiters.wait_for_server_termination,
+ self.client, fake_server['id'])
+
+
class TestImageWaiters(base.TestCase):
def setUp(self):
super(TestImageWaiters, self).setUp()
@@ -145,6 +217,15 @@
waiters.wait_for_image_copied_to_stores,
self.client, 'fake_image_id')
+ def test_wait_for_image_copied_to_stores_status_killed(self):
+ self.client.show_image.return_value = ({
+ 'status': 'killed',
+ 'os_glance_importing_to_stores': None,
+ 'os_glance_failed_import': 'fake_os_glance_failed_import'})
+ self.assertRaises(exceptions.ImageKilledException,
+ waiters.wait_for_image_copied_to_stores,
+ self.client, 'fake_image_id')
+
def test_wait_for_image_tasks_status(self):
self.client.show_image_tasks.return_value = ({
'tasks': [{'status': 'success'}]})
@@ -168,6 +249,28 @@
waiters.wait_for_image_tasks_status,
self.client, 'fake_image_id', 'success')
+ def test_wait_for_tasks_status(self):
+ self.client.show_tasks.return_value = ({
+ 'status': 'success'})
+ start_time = int(time.time())
+ waiters.wait_for_tasks_status(
+ self.client, 'fake_task_id', 'success')
+ end_time = int(time.time())
+ # Ensure waiter returns before build_timeout
+ self.assertLess((end_time - start_time), 10)
+
+ def test_wait_for_tasks_status_timeout(self):
+ time_mock = self.patch('time.time')
+ self.patch('time.time', side_effect=[0., 1.])
+ time_mock.side_effect = utils.generate_timeout_series(1)
+
+ self.client.show_tasks.return_value = (
+ {'status': 'success'},
+ {'status': 'processing'})
+ self.assertRaises(lib_exc.TimeoutException,
+ waiters.wait_for_tasks_status,
+ self.client, 'fake_task_id', 'success')
+
class TestInterfaceWaiters(base.TestCase):
@@ -366,6 +469,31 @@
mock.call(mock.sentinel.volume_id),
mock.call(mock.sentinel.volume_id)])
+ def test_wait_for_volume_retype(self):
+ fake_volume = {'volume_type': {'id': 'fake-uuid'}}
+ show_volume = mock.Mock(return_value={'volume': fake_volume})
+ client = mock.Mock(resource_type="volume",
+ build_interval=1,
+ build_timeout=1,
+ show_volume=show_volume)
+ waiters.wait_for_volume_retype(
+ client, mock.sentinel.volume_id, fake_volume['volume_type'])
+
+ def test_wait_for_volume_retype_timeout(self):
+ fake_volume = {'volume_type': {'id': 'fake-uuid'}}
+ show_volume = mock.Mock(return_value={'volume': fake_volume})
+ client = mock.Mock(resource_type="volume",
+ build_interval=1,
+ build_timeout=1,
+ show_volume=show_volume)
+
+ self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
+ self.patch('time.sleep')
+ self.assertRaises(lib_exc.TimeoutException,
+ waiters.wait_for_volume_retype,
+ client, mock.sentinel.volume_id,
+ 'fake_volume_type')
+
@mock.patch.object(time, 'sleep')
def test_wait_for_volume_status_error_restoring(self, mock_sleep):
# Tests that the wait method raises VolumeRestoreErrorException if
@@ -450,7 +578,25 @@
mock.call(uuids.volume_id),
mock.call(uuids.volume_id)])
- def test_wait_for_volume_attachment(self):
+ def test_wait_for_volume_attachment_create_timeout(self):
+ show_volume = mock.MagicMock(return_value={
+ 'volume': {'attachments': [
+ {'attachment_id': uuids.attachment_id,
+ 'server_id': uuids.server_id,
+ 'volume_id': uuids.volume_id}]}})
+ client = mock.Mock(spec=volumes_client.VolumesClient,
+ build_interval=1,
+ build_timeout=1,
+ show_volume=show_volume)
+ self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
+ self.patch('time.sleep')
+ # Assert that a timeout is raised if the attachment is not
+ # created within required time
+ self.assertRaises(lib_exc.TimeoutException,
+ waiters.wait_for_volume_attachment_create,
+ client, 'fake_volume_id', 'fake_server_id')
+
+ def test_wait_for_volume_attachment_remove(self):
vol_detached = {'volume': {'attachments': []}}
vol_attached = {'volume': {'attachments': [
{'attachment_id': uuids.attachment_id}]}}
@@ -469,7 +615,7 @@
mock.call(uuids.volume_id),
mock.call(uuids.volume_id)])
- def test_wait_for_volume_attachment_timeout(self):
+ def test_wait_for_volume_attachment_remove_timeout(self):
show_volume = mock.MagicMock(return_value={
'volume': {'attachments': [
{'attachment_id': uuids.attachment_id}]}})
@@ -635,6 +781,67 @@
.1
)
+ def test_wait_for_caching(self):
+ mock_client = mock.Mock(
+ build_interval=1,
+ build_timeout=1
+ )
+ mock_cache_client = mock.Mock()
+ mock_cache_client.list_cache.return_value = {
+ "cached_images": [{
+ "image_id": 'fake_image_id'}]}
+ waiters.wait_for_caching(
+ mock_client, mock_cache_client, 'fake_image_id')
+
+ def test_wait_for_caching_timeout(self):
+ time_mock = self.patch('time.time')
+ time_mock.side_effect = utils.generate_timeout_series(1)
+
+ mock_client = mock.Mock(
+ build_interval=1,
+ build_timeout=1
+ )
+ mock_cache_client = mock.Mock()
+ mock_cache_client.list_cache.return_value = {
+ "cached_images": [{
+ "image_id": 'fake_image_id'}]}
+ # Assert that TimeoutException is raised when the image
+ # failed to cache in time
+ self.assertRaises(
+ lib_exc.TimeoutException,
+ waiters.wait_for_caching,
+ mock_client,
+ mock_cache_client,
+ 'fake_image_id'
+ )
+
+ def test_wait_for_object_create(self):
+ mock_object_client = mock.Mock(
+ build_interval=1,
+ build_timeout=1
+ )
+ waiters.wait_for_object_create(
+ mock_object_client, 'fake_container', 'fake_object')
+
+ def test_wait_for_object_create_timeout(self):
+ time_mock = self.patch('time.time')
+ time_mock.side_effect = utils.generate_timeout_series(1)
+
+ mock_object_client = mock.Mock(
+ build_interval=1,
+ build_timeout=1
+ )
+ # Assert that TimeoutException is raised when the object is not
+ # created in time
+ self.assertRaises(
+ lib_exc.TimeoutException,
+ waiters.wait_for_object_create,
+ mock_object_client,
+ 'fake_container',
+ 'fake_object',
+ .1
+ )
+
class TestPortCreationWaiter(base.TestCase):
def test_wait_for_port_status(self):
diff --git a/tempest/tests/lib/common/test_cred_client.py b/tempest/tests/lib/common/test_cred_client.py
index 7ea660b..e44c5ed 100644
--- a/tempest/tests/lib/common/test_cred_client.py
+++ b/tempest/tests/lib/common/test_cred_client.py
@@ -38,6 +38,13 @@
self.projects_client.create_tenant.assert_called_once_with(
name='fake_name', description='desc')
+ def test_show_project(self):
+ self.projects_client.show_tenant.return_value = {
+ 'tenant': 'a_tenant'
+ }
+ res = self.creds_client.show_project('fake_id')
+ self.assertEqual('a_tenant', res)
+
def test_delete_project(self):
self.creds_client.delete_project('fake_id')
self.projects_client.delete_tenant.assert_called_once_with(
@@ -79,11 +86,32 @@
self.projects_client.create_project.assert_called_once_with(
name='fake_name', description='desc', domain_id='fake_domain_id')
+ def test_show_project(self):
+ self.projects_client.show_project.return_value = {
+ 'project': 'a_tenant'
+ }
+ res = self.creds_client.show_project('fake_id')
+ self.assertEqual('a_tenant', res)
+
def test_delete_project(self):
self.creds_client.delete_project('fake_id')
self.projects_client.delete_project.assert_called_once_with(
'fake_id')
+ def test_create_domain(self):
+ self.domains_client.create_domain.return_value = {
+ 'domain': 'a_tenant'
+ }
+ res = self.creds_client.create_domain('fake_name', 'desc')
+ self.assertEqual('a_tenant', res)
+ self.domains_client.create_domain.assert_called_once_with(
+ name='fake_name', description='desc')
+
+ def test_delete_domain(self):
+ self.creds_client.delete_domain('fake_id')
+ self.domains_client.delete_domain.assert_called_once_with(
+ 'fake_id')
+
def test_get_credentials(self):
ret = self.creds_client.get_credentials(
{'name': 'some_user', 'id': 'fake_id'},
diff --git a/tox.ini b/tox.ini
index 47ef5eb..fa32ba3 100644
--- a/tox.ini
+++ b/tox.ini
@@ -64,7 +64,7 @@
coverage combine
coverage html -d cover
coverage xml -o cover/coverage.xml
- coverage report
+ coverage report -m --fail-under=76
[testenv:debug]
commands = oslo_debug_helper -t tempest/tests {posargs}