From 266be4eb4cdd0b3145838b52b73f106cdbd3f805 Mon Sep 17 00:00:00 2001
From: Dhuldev Valekar <dhuldev.valekar@gmail.com>
Date: Mon, 5 Apr 2021 09:12:37 -0500
Subject: [PATCH] Follow up to add iDRAC management via Redfish

Add unit tests to redfish utils method wait_until_get_system_ready.

Followup to change: Iad69c8d7cf3a373f5cfcc619a479a106efa2e4d4

Change-Id: I334d6d5d7a35557a57ba118bed0a6beedba934d3
---
 ironic/drivers/modules/redfish/utils.py       | 32 ++++++++--------
 .../drivers/modules/redfish/test_utils.py     | 37 +++++++++++++++++++
 2 files changed, 54 insertions(+), 15 deletions(-)

diff --git a/ironic/drivers/modules/redfish/utils.py b/ironic/drivers/modules/redfish/utils.py
index 63259a87b9..9479dd34df 100644
--- a/ironic/drivers/modules/redfish/utils.py
+++ b/ironic/drivers/modules/redfish/utils.py
@@ -375,26 +375,28 @@ def get_enabled_macs(task, system):
                   "for node %(node)s", {'node': task.node.uuid})
 
 
-@tenacity.retry(
-    retry=tenacity.retry_if_exception_type(
-        exception.RedfishConnectionError),
-    stop=tenacity.stop_after_attempt(CONF.redfish.connection_attempts),
-    wait=tenacity.wait_fixed(CONF.redfish.connection_retry_interval),
-    reraise=True)
 def wait_until_get_system_ready(node):
     """Wait until Redfish system is ready.
 
     :param node: an Ironic node object
     :raises: RedfishConnectionError on time out.
     """
+    @tenacity.retry(
+        retry=tenacity.retry_if_exception_type(
+            exception.RedfishConnectionError),
+        stop=tenacity.stop_after_attempt(CONF.redfish.connection_attempts),
+        wait=tenacity.wait_fixed(CONF.redfish.connection_retry_interval),
+        reraise=True)
+    def _get_system(driver_info, system_id):
+        try:
+            with SessionCache(driver_info) as conn:
+                return conn.get_system(system_id)
+        except sushy.exceptions.BadRequestError as e:
+            err_msg = ("System is not ready for node %(node)s, with error"
+                       "%(error)s, so retrying it",
+                       {'node': node.uuid, 'error': e})
+            LOG.warning(err_msg)
+            raise exception.RedfishConnectionError(node=node.uuid, error=e)
     driver_info = parse_driver_info(node)
     system_id = driver_info['system_id']
-    try:
-        with SessionCache(driver_info) as conn:
-            return conn.get_system(system_id)
-    except sushy.exceptions.BadRequestError as e:
-        err_msg = ("System is not ready for node %(node)s, with error"
-                   "%(error)s, so retrying it",
-                   {'node': node.uuid, 'error': e})
-        LOG.warning(err_msg)
-        raise exception.RedfishConnectionError(node=node.uuid, error=e)
+    return _get_system(driver_info, system_id)
diff --git a/ironic/tests/unit/drivers/modules/redfish/test_utils.py b/ironic/tests/unit/drivers/modules/redfish/test_utils.py
index 1ea699fd85..837e8a804c 100644
--- a/ironic/tests/unit/drivers/modules/redfish/test_utils.py
+++ b/ironic/tests/unit/drivers/modules/redfish/test_utils.py
@@ -375,3 +375,40 @@ class RedfishUtilsTestCase(db_base.DbTestCase):
 
         self.assertRaises(exception.RedfishError,
                           redfish_utils.get_update_service, self.node)
+
+    @mock.patch.object(time, 'sleep', lambda seconds: None)
+    @mock.patch.object(sushy, 'Sushy', autospec=True)
+    @mock.patch('ironic.drivers.modules.redfish.utils.'
+                'SessionCache._sessions', {})
+    def test_wait_until_get_system_ready(self, mock_sushy):
+        self.config(connection_attempts=2, group='redfish')
+        uri = '/redfish/v1/Systems/FAKESYSTEM'
+        fake_conn = mock_sushy.return_value
+        fake_system = mock.Mock()
+        fake_conn.get_system.side_effect = [
+            sushy.exceptions.BadRequestError('GET', uri, fake_system),
+            fake_system
+        ]
+        response = redfish_utils.wait_until_get_system_ready(self.node)
+        self.assertEqual(fake_system, response)
+        self.assertEqual(fake_conn.get_system.call_count, 2)
+        fake_conn.get_system.assert_called_with(uri)
+
+    @mock.patch.object(time, 'sleep', lambda seconds: None)
+    @mock.patch.object(sushy, 'Sushy', autospec=True)
+    @mock.patch('ironic.drivers.modules.redfish.utils.'
+                'SessionCache._sessions', {})
+    def test_wait_until_get_system_ready_with_connection_error(self,
+                                                               mock_sushy):
+        self.config(connection_attempts=2, group='redfish')
+        uri = '/redfish/v1/Systems/FAKESYSTEM'
+        fake_conn = mock_sushy.return_value
+        fake_system = mock.Mock()
+        fake_conn.get_system.side_effect = [
+            sushy.exceptions.BadRequestError('GET', uri, fake_system),
+            sushy.exceptions.BadRequestError('GET', uri, fake_system)
+        ]
+        self.assertRaises(exception.RedfishConnectionError,
+                          redfish_utils.wait_until_get_system_ready, self.node)
+
+        self.assertEqual(fake_conn.get_system.call_count, 2)