Update the "use storpool's api for attach/detach" patch

Add exception handling tests

Change-Id: I1ea7fcf1470b11af5386fcf87bb1166901df6147
diff --git a/patches/openstack/os-brick/attach-globalid.patch b/patches/openstack/os-brick/attach-globalid.patch
index 71834be..7220b3f 100644
--- a/patches/openstack/os-brick/attach-globalid.patch
+++ b/patches/openstack/os-brick/attach-globalid.patch
@@ -1,4 +1,4 @@
-From 315448f05b310d4e4b2bad084ddcdc888e0c2cd0 Mon Sep 17 00:00:00 2001
+From 1b717bfdcf398792b30980ac94c3770f4acbbe51 Mon Sep 17 00:00:00 2001
 From: Biser Milanov <biser.milanov@storpool.com>
 Date: Tue, 23 May 2023 17:55:09 +0300
 Subject: [PATCH] storpool.py: Use StorPool's API for Attach/Detach
@@ -13,9 +13,9 @@
 
 Change-Id: I0fabcde1dc249b9b09f99ee0b7d759432972314a
 ---
- os_brick/initiator/connectors/storpool.py     |  84 +++++--
- .../initiator/connectors/test_storpool.py     | 219 +++++++++++++-----
- 2 files changed, 236 insertions(+), 67 deletions(-)
+ os_brick/initiator/connectors/storpool.py     |  84 ++++++-
+ .../initiator/connectors/test_storpool.py     | 229 +++++++++++++-----
+ 2 files changed, 246 insertions(+), 67 deletions(-)
 
 diff --git a/os_brick/initiator/connectors/storpool.py b/os_brick/initiator/connectors/storpool.py
 index e1bd55c..9752ad9 100644
@@ -141,10 +141,18 @@
      def get_search_path(self):
          return '/dev/storpool'
 diff --git a/os_brick/tests/initiator/connectors/test_storpool.py b/os_brick/tests/initiator/connectors/test_storpool.py
-index 614deba..b539e2b 100644
+index 614deba..86cf216 100644
 --- a/os_brick/tests/initiator/connectors/test_storpool.py
 +++ b/os_brick/tests/initiator/connectors/test_storpool.py
-@@ -25,46 +25,35 @@ def volumeNameExt(vid):
+@@ -13,6 +13,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++import copy
+ from unittest import mock
+ 
+ 
+@@ -25,46 +26,35 @@ def volumeNameExt(vid):
      return 'os--volume--{id}'.format(id=vid)
  
  
@@ -214,7 +222,7 @@
  
      def volumeName(self, vid):
          return volumeNameExt(vid)
-@@ -74,6 +63,10 @@ spopenstack = mock.Mock()
+@@ -74,6 +64,10 @@ spopenstack = mock.Mock()
  spopenstack.AttachDB = MockStorPoolADB
  connector.spopenstack = spopenstack
  
@@ -225,7 +233,7 @@
  
  class StorPoolConnectorTestCase(test_connector.ConnectorTestCase):
      def volumeName(self, vid):
-@@ -101,6 +94,8 @@ class StorPoolConnectorTestCase(test_connector.ConnectorTestCase):
+@@ -101,38 +95,66 @@ class StorPoolConnectorTestCase(test_connector.ConnectorTestCase):
              'client_id': 1,
              'access_mode': 'rw',
          }
@@ -233,8 +241,12 @@
 +        self.api_calls_retry_max = 10
          self.fakeConnection = None
          self.fakeSize = 1024 * 1024 * 1024
++        self.reassign_wait_data = {'reassign': [
++            {'volume': volumeNameExt(self.fakeProp['volume']),
++             'detach': [1], 'force': False}]}
  
-@@ -109,30 +104,56 @@ class StorPoolConnectorTestCase(test_connector.ConnectorTestCase):
+         self.connector = connector.StorPoolConnector(
+             None, execute=self.execute)
          self.adb = self.connector._attach
  
      def test_connect_volume(self):
@@ -301,17 +313,14 @@
 +                self.adb, attribute='api', spec=['__call__']
 +        ) as fake_api:
 +            fake_api.return_value = api
-+            reassign_wait_data = {'reassign': [
-+                {'volume': volumeNameExt(self.fakeProp['volume']),
-+                 'detach': [1], 'force': False}]}
 +
 +            self.connector.disconnect_volume(self.fakeProp, None)
 +            self.assertEqual(api.volumesReassignWait.mock_calls[0],
-+                             (mock.call(reassign_wait_data)))
++                             (mock.call(self.reassign_wait_data)))
  
      def test_connect_exceptions(self):
          """Raise exceptions on missing connection information"""
-@@ -146,6 +167,96 @@ class StorPoolConnectorTestCase(test_connector.ConnectorTestCase):
+@@ -146,6 +168,105 @@ class StorPoolConnectorTestCase(test_connector.ConnectorTestCase):
                  self.assertRaises(exception.BrickException,
                                    self.connector.disconnect_volume, c, None)
  
@@ -364,46 +373,55 @@
 +                              None)
 +
 +        # Test the retry logic
-+        faulty_api.fail_count = self.api_calls_retry_max - 1
-+        faulty_api.real_fn = mock.MagicMock(spec=['__call__'])
-+        api.volumesReassignWait = faulty_api
-+        api.volumeInfo = mock.MagicMock(spec=['__call__'])
++        def init_mock_api(retries):
++            faulty_api.fail_count = retries
++            faulty_api.real_fn = mock.MagicMock(spec=['__call__'])
++            api.volumesReassignWait = faulty_api
++            api.volumeInfo = mock.MagicMock(spec=['__call__'])
 +
++        init_mock_api(self.api_calls_retry_max - 1)
 +        with mock.patch.object(
 +                self.adb, attribute='api', spec=['__call__']
 +        ) as fake_api:
 +            fake_api.return_value = api
-+            reassign_wait_data = {'reassign': [
-+                {'volume': volumeNameExt(self.fakeProp['volume']),
-+                 'detach': [1], 'force': False}]}
 +
 +            self.connector.disconnect_volume(self.fakeProp, None)
 +            self.assertEqual(self.api_calls_retry_max,
 +                             len(faulty_api.real_fn.mock_calls))
 +            for mock_call in faulty_api.real_fn.mock_calls:
-+                self.assertEqual(mock_call, mock.call(reassign_wait_data))
++                self.assertEqual(mock_call, mock.call(self.reassign_wait_data))
 +
-+        faulty_api.fail_count = self.api_calls_retry_max
-+        faulty_api.real_fn = mock.MagicMock(spec=['__call__'])
-+        api.volumesReassignWait = faulty_api
-+        api.volumeInfo = mock.MagicMock(spec=['__call__'])
-+
++        init_mock_api(self.api_calls_retry_max)
 +        with mock.patch.object(
 +                self.adb, attribute='api', spec=['__call__']
 +        ) as fake_api:
 +            fake_api.return_value = api
-+            reassign_wait_data = {'reassign': [
-+                {'volume': volumeNameExt(self.fakeProp['volume']),
-+                 'detach': [1], 'force': False}]}
++            rwd = copy.deepcopy(self.reassign_wait_data)
 +
 +            self.connector.disconnect_volume(self.fakeProp, None)
 +            self.assertEqual(self.api_calls_retry_max + 1,
 +                             len(faulty_api.real_fn.mock_calls))
 +            for mock_call in faulty_api.real_fn.mock_calls[:-1]:
-+                self.assertEqual(mock_call, mock.call(reassign_wait_data))
-+            reassign_wait_data['reassign'][0]['force'] = True
-+            self.assertEqual(faulty_api.real_fn.mock_calls[-1],
-+                             mock.call(reassign_wait_data))
++                self.assertEqual(mock_call, mock.call(rwd))
++            rwd['reassign'][0]['force'] = True
++            self.assertEqual(faulty_api.real_fn.mock_calls[-1], mock.call(rwd))
++
++        init_mock_api(self.api_calls_retry_max + 1)
++        with mock.patch.object(
++                self.adb, attribute='api', spec=['__call__']
++        ) as fake_api:
++            fake_api.return_value = api
++            rwd = copy.deepcopy(self.reassign_wait_data)
++
++            self.assertRaises(exception.BrickException,
++                              self.connector.disconnect_volume, self.fakeProp,
++                              None)
++            self.assertEqual(self.api_calls_retry_max + 1,
++                             len(faulty_api.real_fn.mock_calls))
++            for mock_call in faulty_api.real_fn.mock_calls[:-1]:
++                self.assertEqual(mock_call, mock.call(rwd))
++            rwd['reassign'][0]['force'] = True
++            self.assertEqual(faulty_api.real_fn.mock_calls[-1], mock.call(rwd))
 +
      def test_extend_volume(self):
          if self.fakeConnection is None: