"Fossies" - the Fresh Open Source Software Archive

Member "cinder-14.0.2/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_replication.py" (4 Oct 2019, 52286 Bytes) of package /linux/misc/openstack/cinder-14.0.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "test_powermax_replication.py": 14.0.2_vs_15.0.0.

    1 # Copyright (c) 2017-2019 Dell Inc. or its subsidiaries.
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 import ast
   17 from copy import deepcopy
   18 
   19 import mock
   20 import six
   21 
   22 from cinder import exception
   23 from cinder import objects
   24 from cinder.objects import fields
   25 from cinder.objects import group
   26 from cinder import test
   27 from cinder.tests.unit.volume.drivers.dell_emc.powermax import (
   28     powermax_data as tpd)
   29 from cinder.tests.unit.volume.drivers.dell_emc.powermax import (
   30     powermax_fake_objects as tpfo)
   31 from cinder.volume.drivers.dell_emc.powermax import common
   32 from cinder.volume.drivers.dell_emc.powermax import fc
   33 from cinder.volume.drivers.dell_emc.powermax import iscsi
   34 from cinder.volume.drivers.dell_emc.powermax import masking
   35 from cinder.volume.drivers.dell_emc.powermax import provision
   36 from cinder.volume.drivers.dell_emc.powermax import rest
   37 from cinder.volume.drivers.dell_emc.powermax import utils
   38 from cinder.volume import utils as volume_utils
   39 
   40 
   41 class PowerMaxReplicationTest(test.TestCase):
   42     def setUp(self):
   43         self.data = tpd.PowerMaxData()
   44         super(PowerMaxReplicationTest, self).setUp()
   45         self.replication_device = {
   46             'target_device_id': self.data.remote_array,
   47             'remote_port_group': self.data.port_group_name_f,
   48             'remote_pool': self.data.srp2,
   49             'rdf_group_label': self.data.rdf_group_name,
   50             'allow_extend': 'True'}
   51         volume_utils.get_max_over_subscription_ratio = mock.Mock()
   52         configuration = tpfo.FakeConfiguration(
   53             None, 'CommonReplicationTests', 1, 1, san_ip='1.1.1.1',
   54             san_login='smc', vmax_array=self.data.array, vmax_srp='SRP_1',
   55             san_password='smc', san_api_port=8443,
   56             vmax_port_groups=[self.data.port_group_name_f],
   57             replication_device=self.replication_device)
   58         rest.PowerMaxRest._establish_rest_session = mock.Mock(
   59             return_value=tpfo.FakeRequestsSession())
   60         driver = fc.PowerMaxFCDriver(configuration=configuration)
   61         iscsi_config = tpfo.FakeConfiguration(
   62             None, 'CommonReplicationTests', 1, 1, san_ip='1.1.1.1',
   63             san_login='smc', vmax_array=self.data.array, vmax_srp='SRP_1',
   64             san_password='smc', san_api_port=8443,
   65             vmax_port_groups=[self.data.port_group_name_i],
   66             replication_device=self.replication_device)
   67         iscsi_driver = iscsi.PowerMaxISCSIDriver(configuration=iscsi_config)
   68         self.iscsi_common = iscsi_driver.common
   69         self.driver = driver
   70         self.common = self.driver.common
   71         self.masking = self.common.masking
   72         self.provision = self.common.provision
   73         self.rest = self.common.rest
   74         self.utils = self.common.utils
   75         self.utils.get_volumetype_extra_specs = (
   76             mock.Mock(
   77                 return_value=self.data.vol_type_extra_specs_rep_enabled))
   78         self.extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
   79         self.extra_specs['retries'] = 1
   80         self.extra_specs['interval'] = 1
   81         self.extra_specs['rep_mode'] = 'Synchronous'
   82         self.async_rep_device = {
   83             'target_device_id': self.data.remote_array,
   84             'remote_port_group': self.data.port_group_name_f,
   85             'remote_pool': self.data.srp2,
   86             'rdf_group_label': self.data.rdf_group_name,
   87             'allow_extend': 'True', 'mode': 'async'}
   88         async_configuration = tpfo.FakeConfiguration(
   89             None, 'CommonReplicationTests', 1, 1, san_ip='1.1.1.1',
   90             san_login='smc', vmax_array=self.data.array, vmax_srp='SRP_1',
   91             san_password='smc', san_api_port=8443,
   92             vmax_port_groups=[self.data.port_group_name_f],
   93             replication_device=self.async_rep_device)
   94         self.async_driver = fc.PowerMaxFCDriver(
   95             configuration=async_configuration)
   96         self.metro_rep_device = {
   97             'target_device_id': self.data.remote_array,
   98             'remote_port_group': self.data.port_group_name_f,
   99             'remote_pool': self.data.srp2,
  100             'rdf_group_label': self.data.rdf_group_name,
  101             'allow_extend': 'True', 'mode': 'metro'}
  102         metro_configuration = tpfo.FakeConfiguration(
  103             None, 'CommonReplicationTests', 1, 1, san_ip='1.1.1.1',
  104             san_login='smc', vmax_array=self.data.array, vmax_srp='SRP_1',
  105             san_password='smc', san_api_port=8443,
  106             vmax_port_groups=[self.data.port_group_name_f],
  107             replication_device=self.metro_rep_device)
  108         self.metro_driver = fc.PowerMaxFCDriver(
  109             configuration=metro_configuration)
  110 
  111     def test_get_replication_info(self):
  112         self.common._get_replication_info()
  113         self.assertTrue(self.common.replication_enabled)
  114 
  115     @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
  116                        return_value=False)
  117     @mock.patch.object(objects.group.Group, 'get_by_id',
  118                        return_value=tpd.PowerMaxData.test_rep_group)
  119     @mock.patch.object(volume_utils, 'is_group_a_type', return_value=True)
  120     @mock.patch.object(utils.PowerMaxUtils, 'check_replication_matched',
  121                        return_value=True)
  122     @mock.patch.object(masking.PowerMaxMasking, 'add_volume_to_storage_group')
  123     @mock.patch.object(
  124         common.PowerMaxCommon, '_replicate_volume',
  125         return_value=({
  126             'replication_driver_data':
  127                 tpd.PowerMaxData.test_volume.replication_driver_data}, {}))
  128     def test_create_replicated_volume(self, mock_rep, mock_add, mock_match,
  129                                       mock_check, mock_get, mock_cg):
  130         extra_specs = deepcopy(self.extra_specs)
  131         extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  132         vol_identifier = self.utils.get_volume_element_name(
  133             self.data.test_volume.id)
  134         self.common.create_volume(self.data.test_volume)
  135         volume_dict = self.data.provider_location
  136         mock_rep.assert_called_once_with(
  137             self.data.test_volume, vol_identifier, volume_dict,
  138             extra_specs)
  139         # Add volume to replication group
  140         self.common.create_volume(self.data.test_volume_group_member)
  141         mock_add.assert_called_once()
  142 
  143     @mock.patch.object(
  144         common.PowerMaxCommon, '_replicate_volume',
  145         return_value=({
  146             'replication_driver_data':
  147                 tpd.PowerMaxData.test_volume.replication_driver_data}, {}))
  148     @mock.patch.object(utils.PowerMaxUtils, 'is_replication_enabled',
  149                        return_value=True)
  150     @mock.patch.object(rest.PowerMaxRest, 'get_rdf_group_number',
  151                        side_effect=['4', None])
  152     def test_create_replicated_vol_side_effect(
  153             self, mock_rdf_no, mock_rep_enabled, mock_rep_vol):
  154         self.common.rep_config = self.utils.get_replication_config(
  155             [self.replication_device])
  156         ref_rep_data = {'array': six.text_type(self.data.remote_array),
  157                         'device_id': self.data.device_id2}
  158         ref_model_update = {
  159             'provider_location': six.text_type(
  160                 self.data.test_volume.provider_location),
  161             'replication_driver_data': six.text_type(ref_rep_data)}
  162         model_update = self.common.create_volume(self.data.test_volume)
  163         self.assertEqual(ref_model_update, model_update)
  164         self.assertRaises(exception.VolumeBackendAPIException,
  165                           self.common.create_volume,
  166                           self.data.test_volume)
  167 
  168     def test_create_cloned_replicated_volume(self):
  169         extra_specs = deepcopy(self.extra_specs)
  170         extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  171         with mock.patch.object(self.common, '_replicate_volume',
  172                                return_value=({}, {})) as mock_rep:
  173             self.common.create_cloned_volume(
  174                 self.data.test_clone_volume, self.data.test_volume)
  175             volume_dict = self.data.provider_location_clone
  176             mock_rep.assert_called_once_with(
  177                 self.data.test_clone_volume,
  178                 self.data.test_clone_volume.name, volume_dict, extra_specs)
  179 
  180     def test_create_replicated_volume_from_snap(self):
  181         extra_specs = deepcopy(self.extra_specs)
  182         extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  183         with mock.patch.object(self.common, '_replicate_volume',
  184                                return_value=({}, {})) as mock_rep:
  185             self.common.create_volume_from_snapshot(
  186                 self.data.test_clone_volume, self.data.test_snapshot)
  187             volume_dict = self.data.provider_location_snapshot
  188             mock_rep.assert_called_once_with(
  189                 self.data.test_clone_volume,
  190                 'snapshot-%s' % self.data.snapshot_id, volume_dict,
  191                 extra_specs)
  192 
  193     def test_replicate_volume(self):
  194         volume_dict = self.data.provider_location
  195         rs_enabled = fields.ReplicationStatus.ENABLED
  196         with mock.patch.object(
  197                 self.common, 'setup_volume_replication',
  198                 return_value=(rs_enabled, {}, {})) as mock_setup:
  199             self.common._replicate_volume(
  200                 self.data.test_volume, '1', volume_dict, self.extra_specs)
  201             mock_setup.assert_called_once_with(
  202                 self.data.array, self.data.test_volume,
  203                 self.data.device_id, self.extra_specs)
  204 
  205     def test_replicate_volume_exception(self):
  206         volume_dict = self.data.provider_location
  207         with mock.patch.object(
  208                 self.common, 'setup_volume_replication',
  209                 side_effect=exception.VolumeBackendAPIException(data='')):
  210             with mock.patch.object(
  211                     self.common, '_cleanup_replication_source') as mock_clean:
  212                 self.assertRaises(
  213                     exception.VolumeBackendAPIException,
  214                     self.common._replicate_volume, self.data.test_volume,
  215                     '1', volume_dict, self.extra_specs)
  216                 mock_clean.assert_called_once_with(
  217                     self.data.array, self.data.test_volume, '1',
  218                     volume_dict, self.extra_specs)
  219 
  220     @mock.patch.object(common.PowerMaxCommon, '_remove_members')
  221     @mock.patch.object(
  222         common.PowerMaxCommon, '_get_replication_extra_specs',
  223         return_value=tpd.PowerMaxData.rep_extra_specs2)
  224     @mock.patch.object(
  225         utils.PowerMaxUtils, 'is_volume_failed_over', return_value=True)
  226     def test_unmap_lun_volume_failed_over(self, mock_fo, mock_es, mock_rm):
  227         extra_specs = deepcopy(self.extra_specs)
  228         extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  229         rep_config = self.utils.get_replication_config(
  230             [self.replication_device])
  231         self.common._unmap_lun(self.data.test_volume, self.data.connector)
  232         mock_es.assert_called_once_with(extra_specs, rep_config)
  233 
  234     @mock.patch.object(common.PowerMaxCommon, '_remove_members')
  235     @mock.patch.object(
  236         common.PowerMaxCommon, '_get_replication_extra_specs',
  237         return_value=tpd.PowerMaxData.rep_extra_specs)
  238     @mock.patch.object(
  239         utils.PowerMaxUtils, 'is_metro_device', return_value=True)
  240     def test_unmap_lun_metro(self, mock_md, mock_es, mock_rm):
  241         extra_specs = deepcopy(self.extra_specs)
  242         extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  243         self.common._unmap_lun(self.data.test_volume, self.data.connector)
  244         self.assertEqual(2, mock_rm.call_count)
  245 
  246     @mock.patch.object(
  247         utils.PowerMaxUtils, 'is_volume_failed_over', return_value=True)
  248     def test_initialize_connection_vol_failed_over(self, mock_fo):
  249         extra_specs = deepcopy(self.extra_specs)
  250         extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  251         rep_extra_specs = deepcopy(tpd.PowerMaxData.rep_extra_specs)
  252         rep_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  253         rep_config = self.utils.get_replication_config(
  254             [self.replication_device])
  255         with mock.patch.object(self.common, '_get_replication_extra_specs',
  256                                return_value=rep_extra_specs) as mock_es:
  257             self.common.initialize_connection(
  258                 self.data.test_volume, self.data.connector)
  259             mock_es.assert_called_once_with(extra_specs, rep_config)
  260 
  261     @mock.patch.object(utils.PowerMaxUtils, 'is_metro_device',
  262                        return_value=True)
  263     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  264                        return_value=('VMAX250F', False))
  265     def test_initialize_connection_vol_metro(self, mock_model, mock_md):
  266         metro_connector = deepcopy(self.data.connector)
  267         metro_connector['multipath'] = True
  268         info_dict = self.common.initialize_connection(
  269             self.data.test_volume, metro_connector)
  270         ref_dict = {'array': self.data.array,
  271                     'device_id': self.data.device_id,
  272                     'hostlunid': 3,
  273                     'maskingview': self.data.masking_view_name_f,
  274                     'metro_hostlunid': 3}
  275         self.assertEqual(ref_dict, info_dict)
  276 
  277     @mock.patch.object(rest.PowerMaxRest, 'get_iscsi_ip_address_and_iqn',
  278                        return_value=([tpd.PowerMaxData.ip],
  279                                      tpd.PowerMaxData.initiator))
  280     @mock.patch.object(common.PowerMaxCommon, '_get_replication_extra_specs',
  281                        return_value=tpd.PowerMaxData.rep_extra_specs)
  282     @mock.patch.object(utils.PowerMaxUtils, 'is_metro_device',
  283                        return_value=True)
  284     def test_initialize_connection_vol_metro_iscsi(self, mock_md, mock_es,
  285                                                    mock_ip):
  286         metro_connector = deepcopy(self.data.connector)
  287         metro_connector['multipath'] = True
  288         info_dict = self.iscsi_common.initialize_connection(
  289             self.data.test_volume, metro_connector)
  290         ref_dict = {'array': self.data.array,
  291                     'device_id': self.data.device_id,
  292                     'hostlunid': 3,
  293                     'maskingview': self.data.masking_view_name_f,
  294                     'ip_and_iqn': [{'ip': self.data.ip,
  295                                     'iqn': self.data.initiator}],
  296                     'metro_hostlunid': 3,
  297                     'is_multipath': True,
  298                     'metro_ip_and_iqn': [{'ip': self.data.ip,
  299                                           'iqn': self.data.initiator}]}
  300         self.assertEqual(ref_dict, info_dict)
  301 
  302     @mock.patch.object(utils.PowerMaxUtils, 'is_metro_device',
  303                        return_value=True)
  304     def test_initialize_connection_no_multipath_iscsi(self, mock_md):
  305         info_dict = self.iscsi_common.initialize_connection(
  306             self.data.test_volume, self.data.connector)
  307         self.assertIsNone(info_dict)
  308 
  309     @mock.patch.object(
  310         masking.PowerMaxMasking, 'pre_multiattach',
  311         return_value=tpd.PowerMaxData.masking_view_dict_multiattach)
  312     def test_attach_metro_volume(self, mock_pre):
  313         rep_extra_specs = deepcopy(tpd.PowerMaxData.rep_extra_specs)
  314         rep_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  315         hostlunid, remote_port_group = self.common._attach_metro_volume(
  316             self.data.test_volume, self.data.connector, False,
  317             self.data.extra_specs, rep_extra_specs)
  318         self.assertEqual(self.data.port_group_name_f, remote_port_group)
  319         # Multiattach case
  320         self.common._attach_metro_volume(
  321             self.data.test_volume, self.data.connector, True,
  322             self.data.extra_specs, rep_extra_specs)
  323         mock_pre.assert_called_once()
  324 
  325     @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
  326                        return_value=(False, False, None))
  327     @mock.patch.object(common.PowerMaxCommon, 'extend_volume_is_replicated')
  328     @mock.patch.object(common.PowerMaxCommon, '_sync_check')
  329     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  330                        return_value=('VMAX250F', False))
  331     def test_extend_volume_rep_enabled(self, mock_model, mock_sync,
  332                                        mock_ex_re, mock_is_re):
  333         extra_specs = deepcopy(self.extra_specs)
  334         extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  335         volume_name = self.data.test_volume.name
  336         self.common.extend_volume(self.data.test_volume, '5')
  337         mock_ex_re.assert_called_once_with(
  338             self.data.array, self.data.test_volume,
  339             self.data.device_id, volume_name, '5', extra_specs)
  340 
  341     def test_set_config_file_get_extra_specs_rep_enabled(self):
  342         extra_specs, _ = self.common._set_config_file_and_get_extra_specs(
  343             self.data.test_volume)
  344         self.assertTrue(extra_specs['replication_enabled'])
  345 
  346     def test_populate_masking_dict_is_re(self):
  347         extra_specs = deepcopy(self.extra_specs)
  348         extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  349         masking_dict = self.common._populate_masking_dict(
  350             self.data.test_volume, self.data.connector, extra_specs)
  351         self.assertTrue(masking_dict['replication_enabled'])
  352         self.assertEqual('OS-HostX-SRP_1-DiamondDSS-OS-fibre-PG-RE',
  353                          masking_dict[utils.SG_NAME])
  354 
  355     @mock.patch.object(common.PowerMaxCommon,
  356                        '_replicate_volume',
  357                        return_value=({}, {}))
  358     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  359                        return_value=('VMAX250F', False))
  360     def test_manage_existing_is_replicated(self, mock_model, mock_rep):
  361         extra_specs = deepcopy(self.extra_specs)
  362         extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  363         external_ref = {u'source-name': u'00002'}
  364         volume_name = self.utils.get_volume_element_name(
  365             self.data.test_volume.id)
  366         provider_location = {'device_id': u'00002', 'array': self.data.array}
  367         with mock.patch.object(
  368                 self.common, '_check_lun_valid_for_cinder_management',
  369                 return_value=(volume_name, 'test_sg')):
  370             self.common.manage_existing(
  371                 self.data.test_volume, external_ref)
  372             mock_rep.assert_called_once_with(
  373                 self.data.test_volume, volume_name, provider_location,
  374                 extra_specs, delete_src=False)
  375 
  376     @mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
  377     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  378                        return_value=('VMAX250F', False))
  379     def test_setup_volume_replication(self, mock_model, mock_rm):
  380         rep_status, rep_data, __ = self.common.setup_volume_replication(
  381             self.data.array, self.data.test_volume, self.data.device_id,
  382             self.extra_specs)
  383         self.assertEqual(fields.ReplicationStatus.ENABLED, rep_status)
  384         self.assertEqual({'array': self.data.remote_array,
  385                           'device_id': self.data.device_id}, rep_data)
  386 
  387     @mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
  388     @mock.patch.object(common.PowerMaxCommon, '_create_volume')
  389     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  390                        return_value=('VMAX250F', False))
  391     def test_setup_volume_replication_target(
  392             self, mock_model, mock_create, mock_rm):
  393         rep_status, rep_data, __ = self.common.setup_volume_replication(
  394             self.data.array, self.data.test_volume, self.data.device_id,
  395             self.extra_specs, self.data.device_id2)
  396         self.assertEqual(fields.ReplicationStatus.ENABLED, rep_status)
  397         self.assertEqual({'array': self.data.remote_array,
  398                           'device_id': self.data.device_id2}, rep_data)
  399         mock_create.assert_not_called()
  400 
  401     @mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
  402                        return_value=(tpd.PowerMaxData.rdf_group_no,
  403                                      tpd.PowerMaxData.remote_array))
  404     @mock.patch.object(rest.PowerMaxRest, 'get_size_of_device_on_array',
  405                        return_value=2)
  406     @mock.patch.object(common.PowerMaxCommon, '_get_replication_extra_specs',
  407                        return_value=tpd.PowerMaxData.rep_extra_specs5)
  408     @mock.patch.object(common.PowerMaxCommon, '_create_volume',
  409                        return_value=tpd.PowerMaxData.provider_location)
  410     @mock.patch.object(common.PowerMaxCommon, '_sync_check')
  411     @mock.patch.object(rest.PowerMaxRest, 'create_rdf_device_pair',
  412                        return_value=tpd.PowerMaxData.rdf_group_details)
  413     def test_setup_inuse_volume_replication(self, mck_create_rdf_pair,
  414                                             mck_sync_chk, mck_create_vol,
  415                                             mck_rep_specs, mck_get_vol_size,
  416                                             mck_get_rdf_info):
  417         array = self.data.array
  418         device_id = self.data.device_id
  419         volume = self.data.test_attached_volume
  420         extra_specs = self.data.extra_specs_migrate
  421         self.rep_config = self.data.rep_extra_specs4
  422         rep_status, rep_data, __ = (
  423             self.common.setup_inuse_volume_replication(
  424                 array, volume, device_id, extra_specs))
  425         self.assertEqual('enabled', rep_status)
  426         self.assertEqual(self.data.rdf_group_details, rep_data)
  427 
  428     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  429                        return_value=('VMAX250F', False))
  430     @mock.patch.object(common.PowerMaxCommon, '_cleanup_remote_target')
  431     def test_cleanup_lun_replication_success(self, mock_clean, mock_model):
  432         rep_extra_specs = deepcopy(self.data.rep_extra_specs)
  433         rep_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
  434         rep_extra_specs['target_array_model'] = 'VMAX250F'
  435         self.common.cleanup_lun_replication(
  436             self.data.test_volume, '1', self.data.device_id,
  437             self.extra_specs)
  438         mock_clean.assert_called_once_with(
  439             self.data.array, self.data.test_volume,
  440             self.data.remote_array, self.data.device_id,
  441             self.data.device_id2, self.data.rdf_group_no, '1',
  442             rep_extra_specs)
  443         # Cleanup legacy replication
  444         self.common.cleanup_lun_replication(
  445             self.data.test_legacy_vol, '1', self.data.device_id,
  446             self.extra_specs)
  447         mock_clean.assert_called_once_with(
  448             self.data.array, self.data.test_volume,
  449             self.data.remote_array, self.data.device_id,
  450             self.data.device_id2, self.data.rdf_group_no, '1',
  451             rep_extra_specs)
  452 
  453     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  454                        return_value=('VMAX250F', False))
  455     @mock.patch.object(common.PowerMaxCommon, '_cleanup_remote_target')
  456     def test_cleanup_lun_replication_no_target(self, mock_clean, mock_model):
  457         with mock.patch.object(self.common, 'get_remote_target_device',
  458                                return_value=(None, '', '', '', '')):
  459             self.common.cleanup_lun_replication(
  460                 self.data.test_volume, '1', self.data.device_id,
  461                 self.extra_specs)
  462             mock_clean.assert_not_called()
  463 
  464     @mock.patch.object(
  465         common.PowerMaxCommon, 'get_remote_target_device',
  466         return_value=(tpd.PowerMaxData.device_id2, '', '', '', ''))
  467     @mock.patch.object(common.PowerMaxCommon,
  468                        '_add_volume_to_async_rdf_managed_grp')
  469     def test_cleanup_lun_replication_exception(self, mock_add, mock_tgt):
  470         self.assertRaises(exception.VolumeBackendAPIException,
  471                           self.common.cleanup_lun_replication,
  472                           self.data.test_volume, '1', self.data.device_id,
  473                           self.extra_specs)
  474         # is metro or async volume
  475         extra_specs = deepcopy(self.extra_specs)
  476         extra_specs[utils.REP_MODE] = utils.REP_METRO
  477         self.assertRaises(exception.VolumeBackendAPIException,
  478                           self.common.cleanup_lun_replication,
  479                           self.data.test_volume, '1', self.data.device_id,
  480                           extra_specs)
  481         mock_add.assert_called_once()
  482 
  483     @mock.patch.object(common.PowerMaxCommon, '_cleanup_metro_target')
  484     @mock.patch.object(masking.PowerMaxMasking,
  485                        'remove_vol_from_storage_group')
  486     @mock.patch.object(common.PowerMaxCommon, '_delete_from_srp')
  487     @mock.patch.object(provision.PowerMaxProvision, 'break_rdf_relationship')
  488     def test_cleanup_remote_target(self, mock_break, mock_del,
  489                                    mock_rm, mock_clean_metro):
  490         with mock.patch.object(self.rest, 'are_vols_rdf_paired',
  491                                return_value=(False, '', '')):
  492             self.common._cleanup_remote_target(
  493                 self.data.array, self.data.test_volume,
  494                 self.data.remote_array, self.data.device_id,
  495                 self.data.device_id2, self.data.rdf_group_name,
  496                 'vol1', self.data.rep_extra_specs)
  497             mock_break.assert_not_called()
  498         self.common._cleanup_remote_target(
  499             self.data.array, self.data.test_volume,
  500             self.data.remote_array, self.data.device_id,
  501             self.data.device_id2, self.data.rdf_group_name,
  502             'vol1', self.data.rep_extra_specs)
  503         mock_break.assert_called_once_with(
  504             self.data.array, self.data.device_id,
  505             self.data.device_id2, self.data.rdf_group_name,
  506             self.data.rep_extra_specs, 'Synchronized')
  507         # is metro volume
  508         with mock.patch.object(self.utils, 'is_metro_device',
  509                                return_value=True):
  510             self.common._cleanup_remote_target(
  511                 self.data.array, self.data.test_volume,
  512                 self.data.remote_array, self.data.device_id,
  513                 self.data.device_id2, self.data.rdf_group_name,
  514                 'vol1', self.data.rep_extra_specs)
  515             mock_clean_metro.assert_called_once()
  516 
  517     def test_cleanup_remote_target_exception(self):
  518         extra_specs = deepcopy(self.data.rep_extra_specs)
  519         extra_specs['mode'] = utils.REP_METRO
  520         self.assertRaises(exception.VolumeBackendAPIException,
  521                           self.metro_driver.common._cleanup_remote_target,
  522                           self.data.array, self.data.test_volume,
  523                           self.data.remote_array,
  524                           self.data.device_id, self.data.device_id2,
  525                           self.data.rdf_group_name, 'vol1', extra_specs)
  526 
  527     @mock.patch.object(provision.PowerMaxProvision, 'enable_group_replication')
  528     @mock.patch.object(rest.PowerMaxRest, 'get_num_vols_in_sg',
  529                        side_effect=[2, 0])
  530     def test_cleanup_metro_target(self, mock_vols, mock_enable):
  531         # allow delete is True
  532         specs = {'allow_del_metro': True}
  533         for x in range(0, 2):
  534             self.common._cleanup_metro_target(
  535                 self.data.array, self.data.device_id, self.data.device_id2,
  536                 self.data.rdf_group_no, specs)
  537             mock_enable.assert_called_once()
  538         # allow delete is False
  539         specs['allow_del_metro'] = False
  540         self.assertRaises(exception.VolumeBackendAPIException,
  541                           self.common._cleanup_metro_target,
  542                           self.data.array, self.data.device_id,
  543                           self.data.device_id2,
  544                           self.data.rdf_group_no, specs)
  545 
  546     @mock.patch.object(common.PowerMaxCommon,
  547                        '_remove_vol_and_cleanup_replication')
  548     @mock.patch.object(masking.PowerMaxMasking,
  549                        'remove_vol_from_storage_group')
  550     @mock.patch.object(common.PowerMaxCommon, '_delete_from_srp')
  551     def test_cleanup_replication_source(self, mock_del, mock_rm, mock_clean):
  552         self.common._cleanup_replication_source(
  553             self.data.array, self.data.test_volume, 'vol1',
  554             {'device_id': self.data.device_id}, self.extra_specs)
  555         mock_del.assert_called_once_with(
  556             self.data.array, self.data.device_id, 'vol1', self.extra_specs)
  557 
  558     def test_get_rdf_details(self):
  559         rdf_group_no, remote_array = self.common.get_rdf_details(
  560             self.data.array)
  561         self.assertEqual(self.data.rdf_group_no, rdf_group_no)
  562         self.assertEqual(self.data.remote_array, remote_array)
  563 
  564     def test_get_rdf_details_exception(self):
  565         with mock.patch.object(self.rest, 'get_rdf_group_number',
  566                                return_value=None):
  567             self.assertRaises(exception.VolumeBackendAPIException,
  568                               self.common.get_rdf_details, self.data.array)
  569 
  570     def test_failover_host(self):
  571         volumes = [self.data.test_volume, self.data.test_clone_volume]
  572         with mock.patch.object(self.common, '_failover_replication',
  573                                return_value=(None, {})) as mock_fo:
  574             self.common.failover_host(volumes)
  575             mock_fo.assert_called_once()
  576 
  577     @mock.patch.object(common.PowerMaxCommon, 'failover_replication',
  578                        return_value=({}, {}))
  579     def test_failover_host_groups(self, mock_fg):
  580         volumes = [self.data.test_volume_group_member]
  581         group1 = self.data.test_group
  582         self.common.failover_host(volumes, None, [group1])
  583         mock_fg.assert_called_once()
  584 
  585     def test_get_remote_target_device(self):
  586         target_device1, _, _, _, _ = (
  587             self.common.get_remote_target_device(
  588                 self.data.array, self.data.test_volume, self.data.device_id))
  589         self.assertEqual(self.data.device_id2, target_device1)
  590         target_device2, _, _, _, _ = (
  591             self.common.get_remote_target_device(
  592                 self.data.array, self.data.test_clone_volume,
  593                 self.data.device_id))
  594         self.assertIsNone(target_device2)
  595         with mock.patch.object(self.rest, 'are_vols_rdf_paired',
  596                                return_value=(False, '')):
  597             target_device3, _, _, _, _ = (
  598                 self.common.get_remote_target_device(
  599                     self.data.array, self.data.test_volume,
  600                     self.data.device_id))
  601             self.assertIsNone(target_device3)
  602         with mock.patch.object(self.rest, 'get_volume',
  603                                return_value=None):
  604             target_device4, _, _, _, _ = (
  605                 self.common.get_remote_target_device(
  606                     self.data.array, self.data.test_volume,
  607                     self.data.device_id))
  608             self.assertIsNone(target_device4)
  609 
  610     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  611                        return_value=('PowerMax 2000', True))
  612     @mock.patch.object(common.PowerMaxCommon, 'setup_volume_replication')
  613     @mock.patch.object(provision.PowerMaxProvision, 'extend_volume')
  614     @mock.patch.object(provision.PowerMaxProvision, 'break_rdf_relationship')
  615     @mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
  616     def test_extend_volume_is_replicated(self, mock_remove, mock_break,
  617                                          mock_extend, mock_setup, mock_model):
  618         self.common.extend_volume_is_replicated(
  619             self.data.array, self.data.test_volume, self.data.device_id,
  620             'vol1', '5', self.data.extra_specs_rep_enabled)
  621         self.assertEqual(2, mock_remove.call_count)
  622         self.assertEqual(2, mock_extend.call_count)
  623         mock_remove.reset_mock()
  624         mock_extend.reset_mock()
  625         with mock.patch.object(self.rest, 'is_next_gen_array',
  626                                return_value=True):
  627             self.common.extend_volume_is_replicated(
  628                 self.data.array, self.data.test_volume, self.data.device_id,
  629                 'vol1', '5', self.data.extra_specs_rep_enabled)
  630             mock_remove.assert_not_called()
  631             self.assertEqual(2, mock_extend.call_count)
  632 
  633     def test_extend_volume_is_replicated_exception(self):
  634         self.assertRaises(exception.VolumeBackendAPIException,
  635                           self.common.extend_volume_is_replicated,
  636                           self.data.failed_resource, self.data.test_volume,
  637                           self.data.device_id, 'vol1', '1',
  638                           self.data.extra_specs_rep_enabled)
  639         with mock.patch.object(self.utils, 'is_metro_device',
  640                                return_value=True):
  641             self.assertRaises(exception.VolumeBackendAPIException,
  642                               self.common.extend_volume_is_replicated,
  643                               self.data.array, self.data.test_volume,
  644                               self.data.device_id, 'vol1', '1',
  645                               self.data.extra_specs_rep_enabled)
  646 
  647     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  648                        return_value=('VMAX250F', False))
  649     @mock.patch.object(common.PowerMaxCommon,
  650                        'add_volume_to_replication_group')
  651     @mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
  652     def test_enable_rdf(self, mock_remove, mock_add, mock_model):
  653         rep_config = self.utils.get_replication_config(
  654             [self.replication_device])
  655         self.common.enable_rdf(
  656             self.data.array, self.data.test_volume, self.data.device_id,
  657             self.data.rdf_group_no, rep_config, 'OS-1',
  658             self.data.remote_array, self.data.device_id2, self.extra_specs)
  659         self.assertEqual(2, mock_remove.call_count)
  660         self.assertEqual(2, mock_add.call_count)
  661 
  662     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  663                        return_value=('VMAX250F', False))
  664     @mock.patch.object(masking.PowerMaxMasking,
  665                        'remove_vol_from_storage_group')
  666     @mock.patch.object(common.PowerMaxCommon, '_cleanup_remote_target')
  667     def test_enable_rdf_exception(self, mock_cleanup, mock_rm, mock_model):
  668         rep_config = self.utils.get_replication_config(
  669             [self.replication_device])
  670         self.assertRaises(
  671             exception.VolumeBackendAPIException, self.common.enable_rdf,
  672             self.data.array, self.data.test_volume, self.data.device_id,
  673             self.data.failed_resource, rep_config, 'OS-1',
  674             self.data.remote_array, self.data.device_id2, self.extra_specs)
  675         self.assertEqual(1, mock_cleanup.call_count)
  676 
  677     def test_add_volume_to_replication_group(self):
  678         sg_name = self.common.add_volume_to_replication_group(
  679             self.data.array, self.data.device_id, 'vol1',
  680             self.extra_specs)
  681         self.assertEqual(self.data.default_sg_re_enabled, sg_name)
  682 
  683     @mock.patch.object(masking.PowerMaxMasking,
  684                        'get_or_create_default_storage_group',
  685                        side_effect=exception.VolumeBackendAPIException)
  686     def test_add_volume_to_replication_group_exception(self, mock_get):
  687         self.assertRaises(
  688             exception.VolumeBackendAPIException,
  689             self.common.add_volume_to_replication_group,
  690             self.data.array, self.data.device_id, 'vol1',
  691             self.extra_specs)
  692 
  693     @mock.patch.object(rest.PowerMaxRest,
  694                        'get_array_model_info',
  695                        return_value=('VMAX250F', False))
  696     def test_get_replication_extra_specs(self, mock_model):
  697         rep_config = self.utils.get_replication_config(
  698             [self.replication_device])
  699         # Path one - disable compression
  700         extra_specs1 = deepcopy(self.extra_specs)
  701         extra_specs1[utils.DISABLECOMPRESSION] = 'true'
  702         ref_specs1 = deepcopy(self.data.rep_extra_specs5)
  703         rep_extra_specs1 = self.common._get_replication_extra_specs(
  704             extra_specs1, rep_config)
  705         self.assertEqual(ref_specs1, rep_extra_specs1)
  706         # Path two - disable compression, not all flash
  707         ref_specs2 = deepcopy(self.data.rep_extra_specs5)
  708         with mock.patch.object(self.rest, 'is_compression_capable',
  709                                return_value=False):
  710             rep_extra_specs2 = self.common._get_replication_extra_specs(
  711                 extra_specs1, rep_config)
  712         self.assertEqual(ref_specs2, rep_extra_specs2)
  713 
  714     @mock.patch.object(rest.PowerMaxRest,
  715                        'get_array_model_info',
  716                        return_value=('PowerMax 2000', True))
  717     def test_get_replication_extra_specs_powermax(self, mock_model):
  718         rep_config = self.utils.get_replication_config(
  719             [self.replication_device])
  720         rep_specs = deepcopy(self.data.rep_extra_specs2)
  721         extra_specs = deepcopy(self.extra_specs)
  722 
  723         # SLO not valid, both SLO and Workload set to NONE
  724         rep_specs['slo'] = None
  725         rep_specs['workload'] = None
  726         rep_specs['target_array_model'] = 'PowerMax 2000'
  727         with mock.patch.object(self.provision, 'verify_slo_workload',
  728                                return_value=(False, False)):
  729             rep_extra_specs = self.common._get_replication_extra_specs(
  730                 extra_specs, rep_config)
  731             self.assertEqual(rep_specs, rep_extra_specs)
  732         # SL valid, workload invalid, only workload set to NONE
  733         rep_specs['slo'] = 'Diamond'
  734         rep_specs['workload'] = None
  735         rep_specs['target_array_model'] = 'PowerMax 2000'
  736         with mock.patch.object(self.provision, 'verify_slo_workload',
  737                                return_value=(True, False)):
  738             rep_extra_specs = self.common._get_replication_extra_specs(
  739                 extra_specs, rep_config)
  740             self.assertEqual(rep_specs, rep_extra_specs)
  741 
  742     def test_get_secondary_stats(self):
  743         rep_config = self.utils.get_replication_config(
  744             [self.replication_device])
  745         array_map = self.common.get_attributes_from_cinder_config()
  746         finalarrayinfolist = self.common._get_slo_workload_combinations(
  747             array_map)
  748         array_info = finalarrayinfolist[0]
  749         ref_info = deepcopy(array_info)
  750         ref_info['SerialNumber'] = six.text_type(rep_config['array'])
  751         ref_info['srpName'] = rep_config['srp']
  752         secondary_info = self.common.get_secondary_stats_info(
  753             rep_config, array_info)
  754         self.assertEqual(ref_info, secondary_info)
  755 
  756     def test_replicate_group(self):
  757         volume_model_update = {
  758             'id': self.data.test_volume.id,
  759             'provider_location': self.data.test_volume.provider_location}
  760         vols_model_update = self.common._replicate_group(
  761             self.data.array, [volume_model_update],
  762             self.data.test_vol_grp_name, self.extra_specs)
  763         ref_rep_data = {'array': self.data.remote_array,
  764                         'device_id': self.data.device_id2}
  765         ref_vol_update = {
  766             'id': self.data.test_volume.id,
  767             'provider_location': self.data.test_volume.provider_location,
  768             'replication_driver_data': ref_rep_data,
  769             'replication_status': fields.ReplicationStatus.ENABLED}
  770 
  771         # Decode string representations of dicts into dicts, because
  772         # the string representations are randomly ordered and therefore
  773         # hard to compare.
  774         vols_model_update[0]['replication_driver_data'] = ast.literal_eval(
  775             vols_model_update[0]['replication_driver_data'])
  776 
  777         self.assertEqual(ref_vol_update, vols_model_update[0])
  778 
  779     @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
  780                        return_value=False)
  781     @mock.patch.object(volume_utils, 'is_group_a_type', return_value=True)
  782     def test_create_replicaton_group(self, mock_type, mock_cg_type):
  783         ref_model_update = {
  784             'status': fields.GroupStatus.AVAILABLE,
  785             'replication_status': fields.ReplicationStatus.ENABLED}
  786         model_update = self.common.create_group(None, self.data.test_group_1)
  787         self.assertEqual(ref_model_update, model_update)
  788         # Replication mode is async
  789         self.assertRaises(exception.InvalidInput,
  790                           self.async_driver.common.create_group,
  791                           None, self.data.test_group_1)
  792 
  793     def test_enable_replication(self):
  794         # Case 1: Group not replicated
  795         with mock.patch.object(volume_utils, 'is_group_a_type',
  796                                return_value=False):
  797             self.assertRaises(NotImplementedError,
  798                               self.common.enable_replication,
  799                               None, self.data.test_group,
  800                               [self.data.test_volume])
  801         with mock.patch.object(volume_utils, 'is_group_a_type',
  802                                return_value=True):
  803             # Case 2: Empty group
  804             model_update, __ = self.common.enable_replication(
  805                 None, self.data.test_group, [])
  806             self.assertEqual({}, model_update)
  807             # Case 3: Successfully enabled
  808             model_update, __ = self.common.enable_replication(
  809                 None, self.data.test_group, [self.data.test_volume])
  810             self.assertEqual(fields.ReplicationStatus.ENABLED,
  811                              model_update['replication_status'])
  812             # Case 4: Exception
  813             model_update, __ = self.common.enable_replication(
  814                 None, self.data.test_group_failed, [self.data.test_volume])
  815             self.assertEqual(fields.ReplicationStatus.ERROR,
  816                              model_update['replication_status'])
  817 
  818     def test_disable_replication(self):
  819         # Case 1: Group not replicated
  820         with mock.patch.object(volume_utils, 'is_group_a_type',
  821                                return_value=False):
  822             self.assertRaises(NotImplementedError,
  823                               self.common.disable_replication,
  824                               None, self.data.test_group,
  825                               [self.data.test_volume])
  826         with mock.patch.object(volume_utils, 'is_group_a_type',
  827                                return_value=True):
  828             # Case 2: Empty group
  829             model_update, __ = self.common.disable_replication(
  830                 None, self.data.test_group, [])
  831             self.assertEqual({}, model_update)
  832             # Case 3: Successfully disabled
  833             model_update, __ = self.common.disable_replication(
  834                 None, self.data.test_group, [self.data.test_volume])
  835             self.assertEqual(fields.ReplicationStatus.DISABLED,
  836                              model_update['replication_status'])
  837             # Case 4: Exception
  838             model_update, __ = self.common.disable_replication(
  839                 None, self.data.test_group_failed, [self.data.test_volume])
  840             self.assertEqual(fields.ReplicationStatus.ERROR,
  841                              model_update['replication_status'])
  842 
  843     def test_failover_replication(self):
  844         with mock.patch.object(volume_utils, 'is_group_a_type',
  845                                return_value=True):
  846             # Case 1: Empty group
  847             model_update, __ = self.common.failover_replication(
  848                 None, self.data.test_group, [])
  849             self.assertEqual({}, model_update)
  850             # Case 2: Successfully failed over
  851             model_update, __ = self.common.failover_replication(
  852                 None, self.data.test_group, [self.data.test_volume])
  853             self.assertEqual(fields.ReplicationStatus.FAILED_OVER,
  854                              model_update['replication_status'])
  855             # Case 3: Successfully failed back
  856             model_update, __ = self.common.failover_replication(
  857                 None, self.data.test_group, [self.data.test_volume],
  858                 secondary_backend_id='default')
  859             self.assertEqual(fields.ReplicationStatus.ENABLED,
  860                              model_update['replication_status'])
  861             # Case 4: Exception
  862             model_update, __ = self.common.failover_replication(
  863                 None, self.data.test_group_failed, [self.data.test_volume])
  864             self.assertEqual(fields.ReplicationStatus.ERROR,
  865                              model_update['replication_status'])
  866 
  867     @mock.patch.object(provision.PowerMaxProvision, 'failover_group')
  868     def test_failover_replication_metro(self, mock_fo):
  869         volumes = [self.data.test_volume]
  870         _, vol_model_updates = self.common._failover_replication(
  871             volumes, group, None, host=True, is_metro=True)
  872         mock_fo.assert_not_called()
  873 
  874     @mock.patch.object(utils.PowerMaxUtils, 'get_volume_group_utils',
  875                        return_value=(tpd.PowerMaxData.array, {}))
  876     @mock.patch.object(common.PowerMaxCommon, '_cleanup_group_replication')
  877     @mock.patch.object(volume_utils, 'is_group_a_type', return_value=True)
  878     def test_delete_replication_group(self, mock_check,
  879                                       mock_cleanup, mock_utils):
  880         self.common._delete_group(self.data.test_rep_group, [])
  881         mock_cleanup.assert_called_once()
  882 
  883     @mock.patch.object(masking.PowerMaxMasking,
  884                        'remove_volumes_from_storage_group')
  885     @mock.patch.object(utils.PowerMaxUtils, 'check_rep_status_enabled')
  886     @mock.patch.object(common.PowerMaxCommon,
  887                        '_remove_remote_vols_from_volume_group')
  888     @mock.patch.object(masking.PowerMaxMasking,
  889                        'add_remote_vols_to_volume_group')
  890     @mock.patch.object(volume_utils, 'is_group_a_type', return_value=True)
  891     @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
  892                        return_value=True)
  893     def test_update_replicated_group(self, mock_cg_type, mock_type_check,
  894                                      mock_add, mock_remove, mock_check,
  895                                      mock_rm):
  896         add_vols = [self.data.test_volume]
  897         remove_vols = [self.data.test_clone_volume]
  898         self.common.update_group(
  899             self.data.test_group_1, add_vols, remove_vols)
  900         mock_add.assert_called_once()
  901         mock_remove.assert_called_once()
  902 
  903     @mock.patch.object(masking.PowerMaxMasking,
  904                        'remove_volumes_from_storage_group')
  905     def test_remove_remote_vols_from_volume_group(self, mock_rm):
  906         self.common._remove_remote_vols_from_volume_group(
  907             self.data.remote_array, [self.data.test_volume],
  908             self.data.test_rep_group, self.data.rep_extra_specs)
  909         mock_rm.assert_called_once()
  910 
  911     @mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
  912     @mock.patch.object(masking.PowerMaxMasking,
  913                        'remove_volumes_from_storage_group')
  914     def test_cleanup_group_replication(self, mock_rm, mock_rm_reset):
  915         self.common._cleanup_group_replication(
  916             self.data.array, self.data.test_vol_grp_name,
  917             [self.data.device_id], self.extra_specs)
  918         mock_rm.assert_called_once()
  919 
  920     @mock.patch.object(masking.PowerMaxMasking, 'add_volume_to_storage_group')
  921     def test_add_volume_to_async_group(self, mock_add):
  922         extra_specs = deepcopy(self.extra_specs)
  923         extra_specs['rep_mode'] = utils.REP_ASYNC
  924         self.async_driver.common._add_volume_to_async_rdf_managed_grp(
  925             self.data.array, self.data.device_id, 'name',
  926             self.data.remote_array, self.data.device_id2, extra_specs)
  927         self.assertEqual(2, mock_add.call_count)
  928 
  929     def test_add_volume_to_async_group_exception(self):
  930         extra_specs = deepcopy(self.extra_specs)
  931         extra_specs['rep_mode'] = utils.REP_ASYNC
  932         self.assertRaises(
  933             exception.VolumeBackendAPIException,
  934             self.async_driver.common._add_volume_to_async_rdf_managed_grp,
  935             self.data.failed_resource, self.data.device_id, 'name',
  936             self.data.remote_array, self.data.device_id2, extra_specs)
  937 
  938     @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
  939                        return_value=('VMAX250F', False))
  940     @mock.patch.object(common.PowerMaxCommon,
  941                        '_add_volume_to_async_rdf_managed_grp')
  942     @mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
  943     def test_setup_volume_replication_async(
  944             self, mock_rm, mock_add, mock_model):
  945         extra_specs = deepcopy(self.extra_specs)
  946         extra_specs['rep_mode'] = utils.REP_ASYNC
  947         rep_status, rep_data, __ = (
  948             self.async_driver.common.setup_volume_replication(
  949                 self.data.array, self.data.test_volume,
  950                 self.data.device_id, extra_specs))
  951         self.assertEqual(fields.ReplicationStatus.ENABLED, rep_status)
  952         self.assertEqual({'array': self.data.remote_array,
  953                           'device_id': self.data.device_id}, rep_data)
  954         mock_add.assert_called_once()
  955 
  956     @mock.patch.object(common.PowerMaxCommon, '_failover_replication',
  957                        return_value=({}, {}))
  958     def test_failover_host_async(self, mock_fg):
  959         volumes = [self.data.test_volume]
  960         extra_specs = deepcopy(self.extra_specs)
  961         extra_specs['rep_mode'] = utils.REP_ASYNC
  962         with mock.patch.object(common.PowerMaxCommon, '_initial_setup',
  963                                return_value=extra_specs):
  964             self.async_driver.common.failover_host(volumes, None, [])
  965         mock_fg.assert_called_once()
  966 
  967     @mock.patch.object(common.PowerMaxCommon, '_retype_volume',
  968                        return_value=True)
  969     @mock.patch.object(masking.PowerMaxMasking,
  970                        'remove_vol_from_storage_group')
  971     @mock.patch.object(common.PowerMaxCommon, '_retype_remote_volume',
  972                        return_value=True)
  973     @mock.patch.object(
  974         common.PowerMaxCommon, 'setup_volume_replication',
  975         return_value=('', tpd.PowerMaxData.provider_location2, ''))
  976     @mock.patch.object(common.PowerMaxCommon,
  977                        '_remove_vol_and_cleanup_replication')
  978     @mock.patch.object(utils.PowerMaxUtils, 'is_replication_enabled',
  979                        side_effect=[False, True, True, False, True, True])
  980     def test_migrate_volume_replication(self, mock_re, mock_rm_rep,
  981                                         mock_setup, mock_retype,
  982                                         mock_rm, mock_rt):
  983         new_type = {'extra_specs': {}}
  984         for x in range(0, 3):
  985             success, model_update = self.common._migrate_volume(
  986                 self.data.array, self.data.test_volume, self.data.device_id,
  987                 self.data.srp, 'OLTP', 'Silver', self.data.test_volume.name,
  988                 new_type, self.data.extra_specs)
  989             self.assertTrue(success)
  990         mock_rm_rep.assert_called_once()
  991         mock_setup.assert_called_once()
  992         mock_retype.assert_called_once()
  993 
  994     @mock.patch.object(
  995         common.PowerMaxCommon, '_get_replication_extra_specs',
  996         return_value=tpd.PowerMaxData.extra_specs_rep_enabled)
  997     @mock.patch.object(rest.PowerMaxRest, 'get_storage_groups_from_volume',
  998                        side_effect=[tpd.PowerMaxData.storagegroup_list,
  999                                     ['OS-SRP_1-Diamond-DSS-RE-SG']])
 1000     @mock.patch.object(common.PowerMaxCommon, '_retype_volume',
 1001                        return_value=True)
 1002     def test_retype_volume_replication(self, mock_retype, mock_sg, mock_es):
 1003         for x in range(0, 2):
 1004             self.common._retype_remote_volume(
 1005                 self.data.array, self.data.test_volume, self.data.device_id,
 1006                 self.data.test_volume.name, utils.REP_SYNC,
 1007                 True, self.data.extra_specs)
 1008         mock_retype.assert_called_once()