summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/common/utils.py4
-rw-r--r--openstackclient/tests/common/test_utils.py40
-rw-r--r--openstackclient/tests/compute/v2/test_server.py57
-rw-r--r--openstackclient/tests/fakes.py97
4 files changed, 195 insertions, 3 deletions
diff --git a/openstackclient/common/utils.py b/openstackclient/common/utils.py
index 8db4f35b..91b1e05a 100644
--- a/openstackclient/common/utils.py
+++ b/openstackclient/common/utils.py
@@ -145,7 +145,6 @@ def format_dict(data):
"""Return a formatted string of key value pairs
:param data: a dict
- :param format: optional formatting hints
:rtype: a string formatted to key='value'
"""
@@ -298,6 +297,7 @@ def wait_for_status(status_f,
res_id,
status_field='status',
success_status=['active'],
+ error_status=['error'],
sleep_time=5,
callback=None):
"""Wait for status change on a resource during a long-running operation
@@ -316,7 +316,7 @@ def wait_for_status(status_f,
if status in success_status:
retval = True
break
- elif status == 'error':
+ elif status in error_status:
retval = False
break
if callback:
diff --git a/openstackclient/tests/common/test_utils.py b/openstackclient/tests/common/test_utils.py
index 373c0de4..b564ffab 100644
--- a/openstackclient/tests/common/test_utils.py
+++ b/openstackclient/tests/common/test_utils.py
@@ -137,6 +137,46 @@ class TestUtils(test_utils.TestCase):
items, sort_str)
@mock.patch.object(time, 'sleep')
+ def test_wait_for_status_ok(self, mock_sleep):
+ # Tests the normal flow that the resource is status=active
+ resource = mock.MagicMock(status='ACTIVE')
+ status_f = mock.Mock(return_value=resource)
+ res_id = str(uuid.uuid4())
+ self.assertTrue(utils.wait_for_status(status_f, res_id,))
+ self.assertFalse(mock_sleep.called)
+
+ @mock.patch.object(time, 'sleep')
+ def test_wait_for_status_ok__with_overrides(self, mock_sleep):
+ # Tests the normal flow that the resource is status=complete
+ resource = mock.MagicMock(my_status='COMPLETE')
+ status_f = mock.Mock(return_value=resource)
+ res_id = str(uuid.uuid4())
+ self.assertTrue(utils.wait_for_status(status_f, res_id,
+ status_field='my_status',
+ success_status=['complete']))
+ self.assertFalse(mock_sleep.called)
+
+ @mock.patch.object(time, 'sleep')
+ def test_wait_for_status_error(self, mock_sleep):
+ # Tests that we fail if the resource is status=error
+ resource = mock.MagicMock(status='ERROR')
+ status_f = mock.Mock(return_value=resource)
+ res_id = str(uuid.uuid4())
+ self.assertFalse(utils.wait_for_status(status_f, res_id))
+ self.assertFalse(mock_sleep.called)
+
+ @mock.patch.object(time, 'sleep')
+ def test_wait_for_status_error_with_overrides(self, mock_sleep):
+ # Tests that we fail if the resource is my_status=failed
+ resource = mock.MagicMock(my_status='FAILED')
+ status_f = mock.Mock(return_value=resource)
+ res_id = str(uuid.uuid4())
+ self.assertFalse(utils.wait_for_status(status_f, res_id,
+ status_field='my_status',
+ error_status=['failed']))
+ self.assertFalse(mock_sleep.called)
+
+ @mock.patch.object(time, 'sleep')
def test_wait_for_delete_ok(self, mock_sleep):
# Tests the normal flow that the resource is deleted with a 404 coming
# back on the 2nd iteration of the wait loop.
diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py
index f6f9797a..791a90ab 100644
--- a/openstackclient/tests/compute/v2/test_server.py
+++ b/openstackclient/tests/compute/v2/test_server.py
@@ -528,6 +528,63 @@ class TestServerImageCreate(TestServer):
self.assertEqual(datalist, data)
+class TestServerPause(TestServer):
+
+ def setUp(self):
+ super(TestServerPause, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.PauseServer(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'pause': None,
+ }
+
+ def setup_servers_mock(self, count=1):
+ servers = fakes.FakeServer.create_servers(methods=self.methods,
+ count=count)
+
+ # This is the return value for utils.find_resource()
+ self.servers_mock.get = fakes.FakeServer.get_servers(servers, 1)
+
+ return servers
+
+ def test_server_pause_one_server(self):
+ servers = self.setup_servers_mock(1)
+
+ arglist = [
+ servers[0].id,
+ ]
+ verifylist = [
+ ('server', [servers[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ self.cmd.take_action(parsed_args)
+
+ servers[0].pause.assert_called_with()
+
+ def test_server_pause_multi_servers(self):
+ servers = self.setup_servers_mock(3)
+ arglist = []
+ verifylist = []
+
+ for i in range(0, len(servers)):
+ arglist.append(servers[i].id)
+ verifylist = [
+ ('server', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ self.cmd.take_action(parsed_args)
+
+ for i in range(0, len(servers)):
+ servers[i].pause.assert_called_with()
+
+
class TestServerResize(TestServer):
def setUp(self):
diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py
index 0f5ef74a..85e65fb1 100644
--- a/openstackclient/tests/fakes.py
+++ b/openstackclient/tests/fakes.py
@@ -13,9 +13,12 @@
# under the License.
#
+import copy
import json
+import mock
import six
import sys
+import uuid
from keystoneauth1 import fixture
import requests
@@ -122,17 +125,41 @@ class FakeModule(object):
class FakeResource(object):
- def __init__(self, manager, info, loaded=False):
+ def __init__(self, manager=None, info={}, loaded=False, methods={}):
+ """Set attributes and methods for a resource.
+
+ :param manager:
+ The resource manager
+ :param Dictionary info:
+ A dictionary with all attributes
+ :param bool loaded:
+ True if the resource is loaded in memory
+ :param Dictionary methods:
+ A dictionary with all methods
+ """
self.__name__ = type(self).__name__
self.manager = manager
self._info = info
self._add_details(info)
+ self._add_methods(methods)
self._loaded = loaded
def _add_details(self, info):
for (k, v) in six.iteritems(info):
setattr(self, k, v)
+ def _add_methods(self, methods):
+ """Fake methods with MagicMock objects.
+
+ For each <@key, @value> pairs in methods, add an callable MagicMock
+ object named @key as an attribute, and set the mock's return_value to
+ @value. When users access the attribute with (), @value will be
+ returned, which looks like a function call.
+ """
+ for (name, ret) in six.iteritems(methods):
+ method = mock.MagicMock(return_value=ret)
+ setattr(self, name, method)
+
def __repr__(self):
reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and
k != 'manager')
@@ -158,3 +185,71 @@ class FakeModel(dict):
return self[key]
except KeyError:
raise AttributeError(key)
+
+
+class FakeServer(object):
+ """Fake one or more compute servers."""
+
+ @staticmethod
+ def create_one_server(attrs={}, methods={}):
+ """Create a fake server.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param Dictionary methods:
+ A dictionary with all methods
+ :return:
+ A FakeResource object, with id, name, metadata
+ """
+ # Set default attributes.
+ server_info = {
+ 'id': 'server-id-' + uuid.uuid4().hex,
+ 'name': 'server-name-' + uuid.uuid4().hex,
+ 'metadata': {},
+ }
+
+ # Overwrite default attributes.
+ server_info.update(attrs)
+
+ server = FakeResource(info=copy.deepcopy(server_info),
+ methods=methods,
+ loaded=True)
+ return server
+
+ @staticmethod
+ def create_servers(attrs={}, methods={}, count=2):
+ """Create multiple fake servers.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param Dictionary methods:
+ A dictionary with all methods
+ :param int count:
+ The number of servers to fake
+ :return:
+ A list of FakeResource objects faking the servers
+ """
+ servers = []
+ for i in range(0, count):
+ servers.append(FakeServer.create_one_server(attrs, methods))
+
+ return servers
+
+ @staticmethod
+ def get_servers(servers=None, count=2):
+ """Get an iterable MagicMock object with a list of faked servers.
+
+ If servers list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List servers:
+ A list of FakeResource objects faking servers
+ :param int count:
+ The number of servers to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ servers
+ """
+ if servers is None:
+ servers = FakeServer.create_servers(count)
+ return mock.MagicMock(side_effect=servers)