From 5903ffff8a56481e124aa4fe8144c16348f6f8b9 Mon Sep 17 00:00:00 2001
From: Mark Vanderwiel <vanderwl@us.ibm.com>
Date: Thu, 28 Jan 2016 10:52:45 -0600
Subject: [PATCH] Allow wait_for_delete to work for all clients

Allow the exception and error status
strings to be passed in such that other plugins can
make use of this function.

There is a comment in find_resource:
  The exception to catch here is dependent on which
  client library the manager passed in belongs to.
  Eventually this should be pulled from a common set
  of client exceptions.

Since I think that is a long ways off, this change will
work now and also work when a common exception is defined
and used.

Change-Id: Iab56cd1166028caed4f1e657e0b1ee81af3f48d8
---
 openstackclient/common/utils.py            |  8 ++++++--
 openstackclient/tests/common/test_utils.py | 22 ++++++++++++++++++++++
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/openstackclient/common/utils.py b/openstackclient/common/utils.py
index 3ae30c8f71..2860608d2d 100644
--- a/openstackclient/common/utils.py
+++ b/openstackclient/common/utils.py
@@ -331,6 +331,8 @@ def wait_for_status(status_f,
 def wait_for_delete(manager,
                     res_id,
                     status_field='status',
+                    error_status=['error'],
+                    exception_name=['NotFound'],
                     sleep_time=5,
                     timeout=300,
                     callback=None):
@@ -341,6 +343,8 @@ def wait_for_delete(manager,
     :param status_field: the status attribute in the returned resource object,
         this is used to check for error states while the resource is being
         deleted
+    :param error_status: a list of status strings for error
+    :param exception_name: a list of exception strings for deleted case
     :param sleep_time: wait this long between checks (seconds)
     :param timeout: check until this long (seconds)
     :param callback: called per sleep cycle, useful to display progress; this
@@ -357,12 +361,12 @@ def wait_for_delete(manager,
             # handle a NotFound exception here without parsing the message
             res = manager.get(res_id)
         except Exception as ex:
-            if type(ex).__name__ == 'NotFound':
+            if type(ex).__name__ in exception_name:
                 return True
             raise
 
         status = getattr(res, status_field, '').lower()
-        if status == 'error':
+        if status in error_status:
             return False
 
         if callback:
diff --git a/openstackclient/tests/common/test_utils.py b/openstackclient/tests/common/test_utils.py
index 064ad417e6..9c02df317f 100644
--- a/openstackclient/tests/common/test_utils.py
+++ b/openstackclient/tests/common/test_utils.py
@@ -212,6 +212,28 @@ class TestUtils(test_utils.TestCase):
         self.assertFalse(utils.wait_for_delete(manager, res_id))
         self.assertFalse(mock_sleep.called)
 
+    @mock.patch.object(time, 'sleep')
+    def test_wait_for_delete_error_with_overrides(self, mock_sleep):
+        # Tests that we fail if the resource is my_status=failed
+        resource = mock.MagicMock(my_status='FAILED')
+        mock_get = mock.Mock(return_value=resource)
+        manager = mock.MagicMock(get=mock_get)
+        res_id = str(uuid.uuid4())
+        self.assertFalse(utils.wait_for_delete(manager, res_id,
+                                               status_field='my_status',
+                                               error_status=['failed']))
+        self.assertFalse(mock_sleep.called)
+
+    @mock.patch.object(time, 'sleep')
+    def test_wait_for_delete_error_with_overrides_exception(self, mock_sleep):
+        # Tests that we succeed if the resource is specific exception
+        mock_get = mock.Mock(side_effect=Exception)
+        manager = mock.MagicMock(get=mock_get)
+        res_id = str(uuid.uuid4())
+        self.assertTrue(utils.wait_for_delete(manager, res_id,
+                                              exception_name=['Exception']))
+        self.assertFalse(mock_sleep.called)
+
     def test_build_kwargs_dict_value_set(self):
         self.assertEqual({'arg_bla': 'bla'},
                          utils.build_kwargs_dict('arg_bla', 'bla'))