text: # Copyright (c) 2020 Dell Inc. or its subsidiaries.
  # All Rights Reserved.
  #
  #    Licensed under the Apache License, Version 2.0 (the "License"); you may
  #    not use this file except in compliance with the License. You may obtain
  #    a copy of the License at
  #
  #         http://www.apache.org/licenses/LICENSE-2.0
  #
  #    Unless required by applicable law or agreed to in writing, software
  #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  #    License for the specific language governing permissions and limitations
  #    under the License.
  
  import ast
  from copy import deepcopy
  import time
  from unittest import mock
  
  import six
  
  from cinder import exception
  from cinder.objects import fields
  from cinder.tests.unit import fake_snapshot
  from cinder.tests.unit import fake_volume
  from cinder.tests.unit import test
  from cinder.tests.unit.volume.drivers.dell_emc.powermax import (
      powermax_data as tpd)
  from cinder.tests.unit.volume.drivers.dell_emc.powermax import (
      powermax_fake_objects as tpfo)
  from cinder.volume.drivers.dell_emc.powermax import common
  from cinder.volume.drivers.dell_emc.powermax import fc
  from cinder.volume.drivers.dell_emc.powermax import masking
  from cinder.volume.drivers.dell_emc.powermax import metadata
  from cinder.volume.drivers.dell_emc.powermax import provision
  from cinder.volume.drivers.dell_emc.powermax import rest
  from cinder.volume.drivers.dell_emc.powermax import utils
  from cinder.volume import volume_utils
  
  
  class PowerMaxCommonTest(test.TestCase):
      def setUp(self):
          self.data = tpd.PowerMaxData()
          super(PowerMaxCommonTest, self).setUp()
          self.mock_object(volume_utils, 'get_max_over_subscription_ratio',
                           return_value=1.0)
          replication_device = self.data.sync_rep_device
          configuration = tpfo.FakeConfiguration(
              emc_file=None, volume_backend_name='CommonTests', interval=1,
              retries=1, san_ip='1.1.1.1', san_login='smc',
              vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
              san_api_port=8443, vmax_port_groups=[self.data.port_group_name_f],
              powermax_port_group_name_template='portGroupName',
              replication_device=replication_device)
          rest.PowerMaxRest._establish_rest_session = mock.Mock(
              return_value=tpfo.FakeRequestsSession())
          driver = fc.PowerMaxFCDriver(configuration=configuration)
          self.driver = driver
          self.common = self.driver.common
          self.masking = self.common.masking
          self.provision = self.common.provision
          self.rest = self.common.rest
          self.utils = self.common.utils
          self.utils.get_volumetype_extra_specs = (
              mock.Mock(return_value=self.data.vol_type_extra_specs))
  
      @mock.patch.object(rest.PowerMaxRest, 'get_array_ucode_version',
                         return_value=tpd.PowerMaxData.next_gen_ucode)
      @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
                         return_value=('PowerMax 2000', True))
      @mock.patch.object(rest.PowerMaxRest, 'set_rest_credentials')
      @mock.patch.object(common.PowerMaxCommon, '_get_slo_workload_combinations',
                         return_value=[])
      @mock.patch.object(common.PowerMaxCommon,
                         'get_attributes_from_cinder_config',
                         side_effect=[[], tpd.PowerMaxData.array_info_wl])
      def test_gather_info_tests(self, mck_parse, mck_combo, mck_rest,
                                 mck_nextgen, mck_ucode):
          # Use-Case 1: Gather info no-opts
          configuration = tpfo.FakeConfiguration(
              None, 'config_group', None, None)
          fc.PowerMaxFCDriver(configuration=configuration)
  
          # Use-Case 2: Gather info next-gen with ucode/version
          self.common._gather_info()
          self.assertTrue(self.common.next_gen)
          self.assertEqual(self.common.ucode_level, self.data.next_gen_ucode)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_array_ucode_version',
                         return_value=tpd.PowerMaxData.next_gen_ucode)
      @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
                         return_value=('PowerMax 2000', True))
      @mock.patch.object(rest.PowerMaxRest, 'set_rest_credentials')
      @mock.patch.object(
          common.PowerMaxCommon, 'get_attributes_from_cinder_config',
          return_value={'SerialNumber': tpd.PowerMaxData.array})
      @mock.patch.object(
          common.PowerMaxCommon, '_get_attributes_from_config')
      def test_gather_info_rep_enabled_duplicate_serial_numbers(
              self, mck_get_cnf, mck_get_c_cnf, mck_set, mck_model, mck_ucode):
          is_enabled = self.common.replication_enabled
          targets = self.common.replication_targets
          self.common.replication_enabled = True
          self.common.replication_targets = [self.data.array]
          self.assertRaises(
              exception.InvalidConfigurationValue, self.common._gather_info)
          self.common.replication_enabled = is_enabled
          self.common.replication_targets = targets
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_gather_info')
      def test_get_attributes_from_config_short_host_template(
              self, mock_gather):
          configuration = tpfo.FakeConfiguration(
              emc_file=None, volume_backend_name='config_group', interval='10',
              retries='10', replication_device=None,
              powermax_short_host_name_template='shortHostName')
          driver = fc.PowerMaxFCDriver(configuration=configuration)
          driver.common._get_attributes_from_config()
          self.assertEqual(
              'shortHostName', driver.common.powermax_short_host_name_template)
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_gather_info')
      def test_get_attributes_from_config_no_short_host_template(
              self, mock_gather):
          configuration = tpfo.FakeConfiguration(
              emc_file=None, volume_backend_name='config_group', interval='10',
              retries='10', replication_device=None)
          driver = fc.PowerMaxFCDriver(configuration=configuration)
          driver.common._get_attributes_from_config()
          self.assertIsNone(driver.common.powermax_short_host_name_template)
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_gather_info')
      def test_get_attributes_from_config_port_group_template(
              self, mock_gather):
          configuration = tpfo.FakeConfiguration(
              emc_file=None, volume_backend_name='config_group', interval='10',
              retries='10', replication_device=None,
              powermax_port_group_name_template='portGroupName')
          driver = fc.PowerMaxFCDriver(configuration=configuration)
          driver.common._get_attributes_from_config()
          self.assertEqual(
              'portGroupName', driver.common.powermax_port_group_name_template)
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_gather_info')
      def test_get_attributes_from_config_no_port_group_template(
              self, mock_gather):
          configuration = tpfo.FakeConfiguration(
              emc_file=None, volume_backend_name='config_group', interval='10',
              retries='10', replication_device=None)
          driver = fc.PowerMaxFCDriver(configuration=configuration)
          driver.common._get_attributes_from_config()
          self.assertIsNone(driver.common.powermax_port_group_name_template)
  
      def test_get_slo_workload_combinations_powermax(self):
          self.common.next_gen = True
          self.common.array_model = 'PowerMax_2000'
          array_info = {}
          pools = self.common._get_slo_workload_combinations(array_info)
          self.assertTrue(len(pools) == 24)
  
      def test_get_slo_workload_combinations_afa_powermax(self):
          self.common.next_gen = True
          self.common.array_model = 'VMAX250F'
          array_info = {}
          pools = self.common._get_slo_workload_combinations(array_info)
          self.assertTrue(len(pools) == 28)
  
      def test_get_slo_workload_combinations_afa_hypermax(self):
          self.common.next_gen = False
          self.common.array_model = 'VMAX250F'
          array_info = {}
          pools = self.common._get_slo_workload_combinations(array_info)
          self.assertTrue(len(pools) == 16)
  
      def test_get_slo_workload_combinations_hybrid(self):
          self.common.next_gen = False
          self.common.array_model = 'VMAX100K'
          array_info = {}
          pools = self.common._get_slo_workload_combinations(array_info)
          self.assertTrue(len(pools) == 44)
  
      def test_get_slo_workload_combinations_failed(self):
          self.common.array_model = 'xxxxxx'
          array_info = {}
          self.assertRaises(
              exception.VolumeBackendAPIException,
              self.common._get_slo_workload_combinations, array_info)
  
      @mock.patch.object(
          common.PowerMaxCommon, 'get_volume_metadata',
          return_value={'device-meta-key-1': 'device-meta-value-1',
                        'device-meta-key-2': 'device-meta-value-2'})
      def test_create_volume(self, mck_meta):
          ref_model_update = (
              {'provider_location': six.text_type(self.data.provider_location),
               'metadata': {'device-meta-key-1': 'device-meta-value-1',
                            'device-meta-key-2': 'device-meta-value-2',
                            'user-meta-key-1': 'user-meta-value-1',
                            'user-meta-key-2': 'user-meta-value-2'}})
          volume = deepcopy(self.data.test_volume)
          volume.metadata = {'user-meta-key-1': 'user-meta-value-1',
                             'user-meta-key-2': 'user-meta-value-2'}
          model_update = self.common.create_volume(volume)
          self.assertEqual(ref_model_update, model_update)
  
      @mock.patch.object(common.PowerMaxCommon, 'get_volume_metadata',
                         return_value=tpd.PowerMaxData.volume_metadata)
      def test_create_volume_qos(self, mck_meta):
          ref_model_update = (
              {'provider_location': six.text_type(self.data.provider_location),
               'metadata': self.data.volume_metadata})
          extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          extra_specs['qos'] = {
              'total_iops_sec': '4000', 'DistributionType': 'Always'}
          with mock.patch.object(self.utils, 'get_volumetype_extra_specs',
                                 return_value=extra_specs):
              model_update = self.common.create_volume(self.data.test_volume)
              self.assertEqual(ref_model_update, model_update)
  
      @mock.patch.object(common.PowerMaxCommon, '_clone_check')
      @mock.patch.object(common.PowerMaxCommon, 'get_volume_metadata',
                         return_value='')
      def test_create_volume_from_snapshot(self, mck_meta, mck_clone_chk):
          ref_model_update = ({'provider_location': six.text_type(
              deepcopy(self.data.provider_location_snapshot))})
          model_update = self.common.create_volume_from_snapshot(
              self.data.test_clone_volume, self.data.test_snapshot)
          self.assertEqual(
              ast.literal_eval(ref_model_update['provider_location']),
              ast.literal_eval(model_update['provider_location']))
  
          # Test from legacy snapshot
          ref_model_update = (
              {'provider_location': six.text_type(
                  deepcopy(self.data.provider_location_clone))})
          model_update = self.common.create_volume_from_snapshot(
              self.data.test_clone_volume, self.data.test_legacy_snapshot)
          self.assertEqual(
              ast.literal_eval(ref_model_update['provider_location']),
              ast.literal_eval(model_update['provider_location']))
  
      @mock.patch.object(common.PowerMaxCommon, 'gather_replication_updates',
                         return_value=(tpd.PowerMaxData.replication_update,
                                       tpd.PowerMaxData.rep_info_dict))
      @mock.patch.object(common.PowerMaxCommon, 'srdf_protect_storage_group')
      @mock.patch.object(provision.PowerMaxProvision, 'create_volume_from_sg',
                         return_value=tpd.PowerMaxData.volume_create_info_dict)
      @mock.patch.object(common.PowerMaxCommon, 'prepare_replication_details',
                         return_value=(True, tpd.PowerMaxData.rep_extra_specs5,
                                       tpd.PowerMaxData.rep_info_dict, True))
      def test_create_replication_enabled_volume_first_volume(
              self, mck_prep, mck_create, mck_protect, mck_updates):
          array = self.data.array
          volume = self.data.test_volume
          volume_name = volume.name
          volume_size = volume.size
          rep_extra_specs = self.data.rep_extra_specs
          rep_extra_specs5 = self.data.rep_extra_specs5
          storagegroup_name = self.data.storagegroup_name_f
          rep_info_dict = self.data.rep_info_dict
          rep_vol = deepcopy(self.data.volume_create_info_dict)
          rep_vol.update({'device_uuid': volume_name,
                          'storage_group': storagegroup_name,
                          'size': volume_size})
          vol, update, info = self.common._create_replication_enabled_volume(
              array, volume, volume_name, volume_size, rep_extra_specs,
              storagegroup_name, rep_extra_specs['rep_mode'])
          mck_prep.assert_called_once_with(self.data.rep_extra_specs)
          mck_create.assert_called_once_with(
              array, volume_name, storagegroup_name, volume_size,
              rep_extra_specs, rep_info_dict)
          mck_protect.assert_called_once_with(
              rep_extra_specs, rep_extra_specs5, rep_vol)
          rep_vol.update({'remote_device_id': self.data.device_id2})
          mck_updates.assert_called_once_with(
              rep_extra_specs, rep_extra_specs5, rep_vol)
          self.assertEqual(self.data.volume_create_info_dict, vol)
          self.assertEqual(self.data.replication_update, update)
          self.assertEqual(self.data.rep_info_dict, info)
  
      @mock.patch.object(common.PowerMaxCommon, '_validate_rdfg_status')
      @mock.patch.object(common.PowerMaxCommon, 'gather_replication_updates',
                         return_value=(tpd.PowerMaxData.replication_update,
                                       tpd.PowerMaxData.rep_info_dict))
      @mock.patch.object(common.PowerMaxCommon, 'srdf_protect_storage_group')
      @mock.patch.object(provision.PowerMaxProvision, 'create_volume_from_sg',
                         return_value=tpd.PowerMaxData.volume_create_info_dict)
      @mock.patch.object(common.PowerMaxCommon, 'prepare_replication_details',
                         side_effect=((False, '', '', True),
                                      ('', tpd.PowerMaxData.rep_extra_specs5,
                                       tpd.PowerMaxData.rep_info_dict, '')))
      def test_create_replication_enabled_volume_not_first_volume(
              self, mck_prepare, mck_create, mck_protect, mck_updates,
              mck_valid):
          array = self.data.array
          volume = self.data.test_volume
          volume_name = volume.name
          volume_size = volume.size
          rep_extra_specs = self.data.rep_extra_specs
          rep_extra_specs5 = self.data.rep_extra_specs5
          storagegroup_name = self.data.storagegroup_name_f
          rep_info_dict = self.data.rep_info_dict
          rep_vol = deepcopy(self.data.volume_create_info_dict)
          rep_vol.update({'device_uuid': volume_name,
                          'storage_group': storagegroup_name,
                          'size': volume_size})
          vol, update, info = self.common._create_replication_enabled_volume(
              array, volume, volume_name, volume_size, rep_extra_specs,
              storagegroup_name, rep_extra_specs['rep_mode'])
          self.assertEqual(2, mck_prepare.call_count)
          mck_create.assert_called_once_with(
              array, volume_name, storagegroup_name, volume_size,
              rep_extra_specs, rep_info_dict)
          mck_protect.assert_not_called()
          mck_valid.assert_called_once_with(array, rep_extra_specs)
          rep_vol.update({'remote_device_id': self.data.device_id2})
          mck_updates.assert_called_once_with(
              rep_extra_specs, rep_extra_specs5, rep_vol)
          self.assertEqual(self.data.volume_create_info_dict, vol)
          self.assertEqual(self.data.replication_update, update)
          self.assertEqual(self.data.rep_info_dict, info)
  
      @mock.patch.object(common.PowerMaxCommon, 'gather_replication_updates',
                         return_value=(tpd.PowerMaxData.replication_update,
                                       tpd.PowerMaxData.rep_info_dict))
      @mock.patch.object(common.PowerMaxCommon, 'get_and_set_remote_device_uuid',
                         return_value=tpd.PowerMaxData.device_id2)
      @mock.patch.object(rest.PowerMaxRest, 'srdf_resume_replication')
      @mock.patch.object(
          common.PowerMaxCommon, 'configure_volume_replication',
          return_value=(None, None, None, tpd.PowerMaxData.rep_extra_specs_mgmt,
                        True))
      @mock.patch.object(common.PowerMaxCommon, 'srdf_protect_storage_group')
      @mock.patch.object(provision.PowerMaxProvision, 'create_volume_from_sg',
                         return_value=tpd.PowerMaxData.volume_create_info_dict)
      @mock.patch.object(common.PowerMaxCommon, 'prepare_replication_details',
                         return_value=(True, {}, {}, False))
      def test_create_replication_enabled_volume_not_first_rdfg_volume(
              self, mck_prepare, mck_create, mck_protect, mck_configure,
              mck_resume, mck_get_set, mck_updates):
  
          array = self.data.array
          volume = self.data.test_volume
          volume_name = volume.name
          volume_size = volume.size
          rep_extra_specs = self.data.rep_extra_specs
          storagegroup_name = self.data.storagegroup_name_f
  
          self.common._create_replication_enabled_volume(
              array, volume, volume_name, volume_size, rep_extra_specs,
              storagegroup_name, rep_extra_specs['rep_mode'])
  
          mck_prepare.assert_called_once()
          mck_protect.assert_not_called()
          mck_configure.assert_called_once()
          mck_resume.assert_called_once()
  
      @mock.patch.object(common.PowerMaxCommon, '_clone_check')
      @mock.patch.object(common.PowerMaxCommon, 'get_volume_metadata',
                         return_value='')
      def test_cloned_volume(self, mck_meta, mck_clone_chk):
          ref_model_update = ({'provider_location': six.text_type(
              self.data.provider_location_clone)})
          model_update = self.common.create_cloned_volume(
              self.data.test_clone_volume, self.data.test_volume)
          self.assertEqual(
              ast.literal_eval(ref_model_update['provider_location']),
              ast.literal_eval(model_update['provider_location']))
  
      def test_delete_volume(self):
          with mock.patch.object(self.common, '_delete_volume') as mock_delete:
              self.common.delete_volume(self.data.test_volume)
              mock_delete.assert_called_once_with(self.data.test_volume)
  
      @mock.patch.object(common.PowerMaxCommon, '_clone_check')
      @mock.patch.object(
          common.PowerMaxCommon, 'get_snapshot_metadata',
          return_value={'snap-meta-key-1': 'snap-meta-value-1',
                        'snap-meta-key-2': 'snap-meta-value-2'})
      def test_create_snapshot(self, mck_meta, mck_clone_chk):
          ref_model_update = (
              {'provider_location': six.text_type(self.data.snap_location),
               'metadata': {'snap-meta-key-1': 'snap-meta-value-1',
                            'snap-meta-key-2': 'snap-meta-value-2',
                            'user-meta-key-1': 'user-meta-value-1',
                            'user-meta-key-2': 'user-meta-value-2'}})
          snapshot = deepcopy(self.data.test_snapshot_manage)
          snapshot.metadata = {'user-meta-key-1': 'user-meta-value-1',
                               'user-meta-key-2': 'user-meta-value-2'}
          model_update = self.common.create_snapshot(
              snapshot, self.data.test_volume)
          self.assertEqual(ref_model_update, model_update)
  
      def test_delete_snapshot(self):
          snap_name = self.data.snap_location['snap_name']
          sourcedevice_id = self.data.snap_location['source_id']
          generation = 0
          with mock.patch.object(
                  self.provision, 'delete_volume_snap') as mock_delete_snap:
              self.common.delete_snapshot(
                  self.data.test_snapshot, self.data.test_volume)
              mock_delete_snap.assert_called_once_with(
                  self.data.array, snap_name, [sourcedevice_id],
                  restored=False, generation=generation)
  
      def test_delete_snapshot_not_found(self):
          with mock.patch.object(self.common, '_parse_snap_info',
                                 return_value=(None, 'Something')):
              with mock.patch.object(
                      self.provision, 'delete_volume_snap') as mock_delete_snap:
                  self.common.delete_snapshot(self.data.test_snapshot,
                                              self.data.test_volume)
                  mock_delete_snap.assert_not_called()
  
      def test_delete_legacy_snap(self):
          with mock.patch.object(self.common, '_delete_volume') as mock_del:
              self.common.delete_snapshot(self.data.test_legacy_snapshot,
                                          self.data.test_legacy_vol)
              mock_del.assert_called_once_with(self.data.test_legacy_snapshot)
  
      @mock.patch.object(masking.PowerMaxMasking,
                         'return_volume_to_fast_managed_group')
      @mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
      def test_remove_members(self, mock_rm, mock_return):
          array = self.data.array
          device_id = self.data.device_id
          volume = self.data.test_volume
          volume_name = self.data.test_volume.name
          extra_specs = self.data.extra_specs
          self.common._remove_members(
              array, volume, device_id, extra_specs, self.data.connector, False)
          mock_rm.assert_called_once_with(
              array, volume, device_id, volume_name,
              extra_specs, True, self.data.connector, async_grp=None,
              host_template=None)
  
      @mock.patch.object(masking.PowerMaxMasking,
                         'return_volume_to_fast_managed_group')
      @mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
      def test_remove_members_multiattach_case(self, mock_rm, mock_return):
          array = self.data.array
          device_id = self.data.device_id
          volume = self.data.test_volume
          volume_name = self.data.test_volume.name
          extra_specs = self.data.extra_specs
          self.common._remove_members(
              array, volume, device_id, extra_specs, self.data.connector, True)
          mock_rm.assert_called_once_with(
              array, volume, device_id, volume_name,
              extra_specs, False, self.data.connector, async_grp=None,
              host_template=None)
          mock_return.assert_called_once()
  
      def test_unmap_lun(self):
          array = self.data.array
          device_id = self.data.device_id
          volume = self.data.test_volume
          extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          connector = self.data.connector
          with mock.patch.object(self.common, '_remove_members') as mock_remove:
              self.common._unmap_lun(volume, connector)
              mock_remove.assert_called_once_with(
                  array, volume, device_id, extra_specs,
                  connector, False, async_grp=None, host_template=None)
  
      def test_unmap_lun_force(self):
          volume = self.data.test_volume
          extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          connector = deepcopy(self.data.connector)
          del connector['host']
          with mock.patch.object(
                  self.common.utils, 'get_host_short_name') as mock_host:
              self.common._unmap_lun(volume, connector)
              mock_host.assert_not_called()
  
      @mock.patch.object(common.PowerMaxCommon, '_remove_members')
      def test_unmap_lun_attachments(self, mock_rm):
          volume1 = deepcopy(self.data.test_volume)
          volume1.volume_attachment.objects = [self.data.test_volume_attachment]
          connector = self.data.connector
          self.common._unmap_lun(volume1, connector)
          mock_rm.assert_called_once()
          mock_rm.reset_mock()
          volume2 = deepcopy(volume1)
          volume2.volume_attachment.objects.append(
              self.data.test_volume_attachment)
          self.common._unmap_lun(volume2, connector)
          mock_rm.assert_not_called()
  
      def test_unmap_lun_qos(self):
          array = self.data.array
          device_id = self.data.device_id
          volume = self.data.test_volume
          extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          extra_specs['qos'] = {
              'total_iops_sec': '4000', 'DistributionType': 'Always'}
          connector = self.data.connector
          with mock.patch.object(self.common, '_remove_members') as mock_remove:
              with mock.patch.object(self.utils, 'get_volumetype_extra_specs',
                                     return_value=extra_specs):
                  self.common._unmap_lun(volume, connector)
                  mock_remove.assert_called_once_with(
                      array, volume, device_id, extra_specs,
                      connector, False, async_grp=None, host_template=None)
  
      def test_unmap_lun_not_mapped(self):
          volume = self.data.test_volume
          connector = self.data.connector
          with mock.patch.object(self.common, 'find_host_lun_id',
                                 return_value=({}, False)):
              with mock.patch.object(
                      self.common, '_remove_members') as mock_remove:
                  self.common._unmap_lun(volume, connector)
                  mock_remove.assert_not_called()
  
      def test_unmap_lun_connector_is_none(self):
          array = self.data.array
          device_id = self.data.device_id
          volume = self.data.test_volume
          extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          extra_specs['storagetype:portgroupname'] = (
              self.data.port_group_name_f)
          with mock.patch.object(self.common, '_remove_members') as mock_remove:
              self.common._unmap_lun(volume, None)
              mock_remove.assert_called_once_with(
                  array, volume, device_id, extra_specs, None,
                  False, async_grp=None, host_template=None)
  
      @mock.patch.object(metadata.PowerMaxVolumeMetadata, 'capture_detach_info')
      @mock.patch.object(common.PowerMaxCommon, '_remove_members')
      def test_unmap_lun_multiattach_prints_metadata(self, mck_remove, mck_info):
          volume = deepcopy(self.data.test_volume)
          connector = deepcopy(self.data.connector)
          volume.volume_attachment.objects = [
              deepcopy(self.data.test_volume_attachment),
              deepcopy(self.data.test_volume_attachment)]
          self.common._unmap_lun(volume, connector)
          self.assertEqual(0, mck_remove.call_count)
          self.assertEqual(1, mck_info.call_count)
  
      @mock.patch.object(provision.PowerMaxProvision, 'verify_slo_workload')
      @mock.patch.object(common.PowerMaxCommon, '_remove_members')
      @mock.patch.object(common.PowerMaxCommon, 'find_host_lun_id',
                         return_value=(tpd.PowerMaxData.iscsi_device_info,
                                       False))
      @mock.patch.object(
          common.PowerMaxCommon, '_get_replication_extra_specs',
          return_value=tpd.PowerMaxData.rep_extra_specs_rep_config)
      @mock.patch.object(
          common.PowerMaxCommon, '_initial_setup',
          return_value=tpd.PowerMaxData.rep_extra_specs_rep_config)
      def test_unmap_lun_replication_force_flag(
              self, mck_setup, mck_rep, mck_find, mck_rem, mck_slo):
          volume = deepcopy(self.data.test_volume)
          connector = deepcopy(self.data.connector)
          device_info = self.data.provider_location['device_id']
          volume.volume_attachment.objects = [
              deepcopy(self.data.test_volume_attachment)]
          extra_specs = deepcopy(self.data.rep_extra_specs_rep_config)
          array = extra_specs[utils.ARRAY]
          extra_specs[utils.FORCE_VOL_REMOVE] = True
          self.common._unmap_lun(volume, connector)
          mck_rem.assert_called_once_with(array, volume, device_info,
                                          extra_specs, connector, False,
                                          async_grp=None, host_template=None)
  
      def test_initialize_connection_already_mapped(self):
          volume = self.data.test_volume
          connector = self.data.connector
          host_lun = (self.data.maskingview[0]['maskingViewConnection'][0][
              'host_lun_address'])
          ref_dict = {'hostlunid': int(host_lun, 16),
                      'maskingview': self.data.masking_view_name_f,
                      'array': self.data.array,
                      'device_id': self.data.device_id}
          device_info_dict = self.common.initialize_connection(volume, connector)
          self.assertEqual(ref_dict, device_info_dict)
  
      def test_initialize_connection_setup_init_conn(self):
          volume = self.data.test_volume
          connector = self.data.connector
          with mock.patch.object(
                  self.common, '_initial_setup',
                  side_effect=self.common._initial_setup) as mck_setup:
              self.common.initialize_connection(volume, connector)
              mck_setup.assert_called_once_with(volume, init_conn=True)
  
      def test_initialize_connection_already_mapped_next_gen(self):
          with mock.patch.object(self.rest, 'is_next_gen_array',
                                 return_value=True):
              volume = self.data.test_volume
              connector = self.data.connector
              host_lun = (self.data.maskingview[0]['maskingViewConnection'][0][
                  'host_lun_address'])
              ref_dict = {'hostlunid': int(host_lun, 16),
                          'maskingview': self.data.masking_view_name_f,
                          'array': self.data.array,
                          'device_id': self.data.device_id}
              device_info_dict = self.common.initialize_connection(volume,
                                                                   connector)
              self.assertEqual(ref_dict, device_info_dict)
  
      @mock.patch.object(common.PowerMaxCommon, 'find_host_lun_id',
                         return_value=({}, False))
      @mock.patch.object(
          common.PowerMaxCommon, '_attach_volume',
          return_value=({}, tpd.PowerMaxData.port_group_name_f))
      def test_initialize_connection_not_mapped(self, mock_attach, mock_id):
          volume = self.data.test_volume
          connector = self.data.connector
          extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          masking_view_dict = self.common._populate_masking_dict(
              volume, connector, extra_specs)
          masking_view_dict[utils.IS_MULTIATTACH] = False
          device_info_dict = self.common.initialize_connection(
              volume, connector)
          self.assertEqual({}, device_info_dict)
          mock_attach.assert_called_once_with(
              volume, connector, extra_specs, masking_view_dict)
  
      @mock.patch.object(rest.PowerMaxRest, 'is_next_gen_array',
                         return_value=True)
      @mock.patch.object(common.PowerMaxCommon, 'find_host_lun_id',
                         return_value=({}, False))
      @mock.patch.object(
          common.PowerMaxCommon, '_attach_volume',
          return_value=({}, tpd.PowerMaxData.port_group_name_f))
      def test_initialize_connection_not_mapped_next_gen(self, mock_attach,
                                                         mock_id, mck_gen):
          volume = self.data.test_volume
          connector = self.data.connector
          device_info_dict = self.common.initialize_connection(
              volume, connector)
          self.assertEqual({}, device_info_dict)
  
      @mock.patch.object(
          masking.PowerMaxMasking, 'pre_multiattach',
          return_value=tpd.PowerMaxData.masking_view_dict_multiattach)
      @mock.patch.object(common.PowerMaxCommon, 'find_host_lun_id',
                         return_value=({}, True))
      @mock.patch.object(
          common.PowerMaxCommon, '_attach_volume',
          return_value=({}, tpd.PowerMaxData.port_group_name_f))
      def test_initialize_connection_multiattach_case(
              self, mock_attach, mock_id, mock_pre):
          volume = self.data.test_volume
          connector = self.data.connector
          self.common.initialize_connection(volume, connector)
          mock_attach.assert_called_once()
          mock_pre.assert_called_once()
  
      def test_attach_volume_success(self):
          volume = self.data.test_volume
          connector = self.data.connector
          extra_specs = deepcopy(self.data.extra_specs)
          extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          masking_view_dict = self.common._populate_masking_dict(
              volume, connector, extra_specs)
          host_lun = (self.data.maskingview[0]['maskingViewConnection'][0][
              'host_lun_address'])
          ref_dict = {'hostlunid': int(host_lun, 16),
                      'maskingview': self.data.masking_view_name_f,
                      'array': self.data.array,
                      'device_id': self.data.device_id}
          with mock.patch.object(self.masking, 'setup_masking_view',
                                 return_value={
                                     utils.PORTGROUPNAME:
                                         self.data.port_group_name_f}):
              device_info_dict, pg = self.common._attach_volume(
                  volume, connector, extra_specs, masking_view_dict)
          self.assertEqual(ref_dict, device_info_dict)
  
      @mock.patch.object(masking.PowerMaxMasking,
                         'check_if_rollback_action_for_masking_required')
      @mock.patch.object(masking.PowerMaxMasking, 'setup_masking_view',
                         return_value={})
      @mock.patch.object(common.PowerMaxCommon, 'find_host_lun_id',
                         return_value=({}, False))
      def test_attach_volume_failed(self, mock_lun, mock_setup, mock_rollback):
          volume = self.data.test_volume
          connector = self.data.connector
          extra_specs = deepcopy(self.data.extra_specs)
          extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          masking_view_dict = self.common._populate_masking_dict(
              volume, connector, extra_specs)
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common._attach_volume, volume,
                            connector, extra_specs, masking_view_dict)
          device_id = self.data.device_id
          (mock_rollback.assert_called_once_with(
              self.data.array, volume, device_id, {}))
  
      def test_terminate_connection(self):
          volume = self.data.test_volume
          connector = self.data.connector
          with mock.patch.object(self.common, '_unmap_lun') as mock_unmap:
              self.common.terminate_connection(volume, connector)
              mock_unmap.assert_called_once_with(
                  volume, connector)
  
      @mock.patch.object(provision.PowerMaxProvision, 'extend_volume')
      @mock.patch.object(common.PowerMaxCommon, '_extend_vol_validation_checks')
      def test_extend_vol_no_rep_success(self, mck_val_chk, mck_extend):
          volume = self.data.test_volume
          array = self.data.array
          device_id = self.data.device_id
          new_size = self.data.test_volume.size
          ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          self.common.extend_volume(volume, new_size)
          mck_extend.assert_called_once_with(
              array, device_id, new_size, ref_extra_specs, None)
  
      @mock.patch.object(common.PowerMaxCommon, '_validate_rdfg_status')
      @mock.patch.object(provision.PowerMaxProvision, 'extend_volume')
      @mock.patch.object(common.PowerMaxCommon, '_array_ode_capabilities_check',
                         return_value=[True] * 4)
      @mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
                         return_value=('1', None))
      @mock.patch.object(common.PowerMaxCommon, '_extend_vol_validation_checks')
      @mock.patch.object(common.PowerMaxCommon, '_initial_setup',
                         return_value=tpd.PowerMaxData.ex_specs_rep_config)
      def test_extend_vol_rep_success_next_gen(
              self, mck_setup, mck_val_chk, mck_get_rdf, mck_ode, mck_extend,
              mck_validate):
          self.common.next_gen = True
          volume = self.data.test_volume
          array = self.data.array
          device_id = self.data.device_id
          new_size = self.data.test_volume.size
          ref_extra_specs = deepcopy(self.data.ex_specs_rep_config)
          ref_extra_specs['array'] = self.data.array
  
          self.common.extend_volume(volume, new_size)
          mck_extend.assert_called_once_with(
              array, device_id, new_size, ref_extra_specs, '1')
          mck_ode.assert_called_once_with(
              array, ref_extra_specs[utils.REP_CONFIG], True)
          mck_validate.assert_called_once_with(array, ref_extra_specs)
  
      @mock.patch.object(common.PowerMaxCommon, '_validate_rdfg_status')
      @mock.patch.object(provision.PowerMaxProvision, 'extend_volume')
      @mock.patch.object(common.PowerMaxCommon, '_extend_legacy_replicated_vol')
      @mock.patch.object(common.PowerMaxCommon, '_array_ode_capabilities_check',
                         return_value=[True, True, False, False])
      @mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
                         return_value=('1', None))
      @mock.patch.object(common.PowerMaxCommon, '_extend_vol_validation_checks')
      @mock.patch.object(common.PowerMaxCommon, '_initial_setup',
                         return_value=tpd.PowerMaxData.ex_specs_rep_config)
      def test_extend_vol_rep_success_next_gen_legacy_r2(
              self, mck_setup, mck_val_chk, mck_get_rdf, mck_ode, mck_leg_extend,
              mck_extend, mck_validate):
          self.common.next_gen = True
          self.common.rep_config = self.data.rep_config
          volume = self.data.test_volume
          array = self.data.array
          device_id = self.data.device_id
          new_size = self.data.test_volume.size
          ref_extra_specs = deepcopy(self.data.ex_specs_rep_config)
          ref_extra_specs['array'] = self.data.array
  
          self.common.extend_volume(volume, new_size)
          mck_leg_extend.assert_called_once_with(
              array, volume, device_id, volume.name, new_size,
              ref_extra_specs, '1')
          mck_ode.assert_called_once_with(
              array, ref_extra_specs[utils.REP_CONFIG], True)
          mck_extend.assert_not_called()
          mck_validate.assert_called_once_with(array, ref_extra_specs)
  
      @mock.patch.object(common.PowerMaxCommon, '_validate_rdfg_status')
      @mock.patch.object(provision.PowerMaxProvision, 'extend_volume')
      @mock.patch.object(common.PowerMaxCommon, '_extend_legacy_replicated_vol')
      @mock.patch.object(common.PowerMaxCommon, '_array_ode_capabilities_check',
                         return_value=[False, False, False, False])
      @mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
                         return_value=('1', None))
      @mock.patch.object(common.PowerMaxCommon, '_extend_vol_validation_checks')
      @mock.patch.object(common.PowerMaxCommon, '_initial_setup',
                         return_value=tpd.PowerMaxData.ex_specs_rep_config)
      def test_extend_vol_rep_success_legacy(
              self, mck_setup, mck_val_chk, mck_get_rdf, mck_ode, mck_leg_extend,
              mck_extend, mck_validate):
          self.common.rep_config = self.data.rep_config
          self.common.next_gen = False
          volume = self.data.test_volume
          array = self.data.array
          device_id = self.data.device_id
          new_size = self.data.test_volume.size
          ref_extra_specs = deepcopy(self.data.ex_specs_rep_config)
          ref_extra_specs['array'] = self.data.array
  
          self.common.extend_volume(volume, new_size)
          mck_leg_extend.assert_called_once_with(
              array, volume, device_id, volume.name, new_size,
              ref_extra_specs, '1')
          mck_ode.assert_called_once_with(
              array, ref_extra_specs[utils.REP_CONFIG], True)
          mck_extend.assert_not_called()
          mck_validate.assert_called_once_with(array, ref_extra_specs)
  
      @mock.patch.object(common.PowerMaxCommon, '_validate_rdfg_status')
      @mock.patch.object(common.PowerMaxCommon, '_array_ode_capabilities_check',
                         return_value=[False, False, False, False])
      @mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
                         return_value=('1', None))
      @mock.patch.object(common.PowerMaxCommon, '_extend_vol_validation_checks')
      @mock.patch.object(
          common.PowerMaxCommon, '_initial_setup',
          return_value=tpd.PowerMaxData.ex_specs_rep_config_no_extend)
      def test_extend_vol_rep_success_legacy_allow_extend_false(
              self, mck_setup, mck_val_chk, mck_get_rdf, mck_ode, mck_validate):
          self.common.rep_config = self.data.rep_config
          self.common.next_gen = False
          volume = self.data.test_volume
          new_size = self.data.test_volume.size
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common.extend_volume, volume, new_size)
  
      def test_update_volume_stats(self):
          data = self.common.update_volume_stats()
          self.assertEqual('CommonTests', data['volume_backend_name'])
  
      def test_update_volume_stats_no_wlp(self):
          with mock.patch.object(self.common, '_update_srp_stats',
                                 return_value=('123s#SRP_1#None#None',
                                               100, 90, 90, 10)):
              data = self.common.update_volume_stats()
              self.assertEqual('CommonTests', data['volume_backend_name'])
  
      def test_update_srp_stats_with_wl(self):
          with mock.patch.object(self.rest, 'get_srp_by_name',
                                 return_value=self.data.srp_details):
              location_info, __, __, __, __ = self.common._update_srp_stats(
                  self.data.array_info_wl)
              self.assertEqual(location_info, '000197800123#SRP_1#Diamond#OLTP')
  
      def test_update_srp_stats_no_wl(self):
          with mock.patch.object(self.rest, 'get_srp_by_name',
                                 return_value=self.data.srp_details):
              location_info, __, __, __, __ = self.common._update_srp_stats(
                  self.data.array_info_no_wl)
              self.assertEqual(location_info, '000197800123#SRP_1#Diamond')
  
      def test_find_device_on_array_success(self):
          volume = self.data.test_volume
          extra_specs = self.data.extra_specs
          ref_device_id = self.data.device_id
          founddevice_id = self.common._find_device_on_array(volume, extra_specs)
          self.assertEqual(ref_device_id, founddevice_id)
  
      def test_find_device_on_array_provider_location_not_string(self):
          volume = fake_volume.fake_volume_obj(
              context='cxt', provider_location=None)
          extra_specs = self.data.extra_specs
          founddevice_id = self.common._find_device_on_array(
              volume, extra_specs)
          self.assertIsNone(founddevice_id)
  
      def test_find_legacy_device_on_array(self):
          volume = self.data.test_legacy_vol
          extra_specs = self.data.extra_specs
          ref_device_id = self.data.device_id
          founddevice_id = self.common._find_device_on_array(volume, extra_specs)
          self.assertEqual(ref_device_id, founddevice_id)
  
      def test_find_host_lun_id_attached(self):
          volume = self.data.test_volume
          extra_specs = self.data.extra_specs
          host = 'HostX'
          host_lun = (
              self.data.maskingview[0]['maskingViewConnection'][0][
                  'host_lun_address'])
          ref_masked = {'hostlunid': int(host_lun, 16),
                        'maskingview': self.data.masking_view_name_f,
                        'array': self.data.array,
                        'device_id': self.data.device_id}
          maskedvols, __ = self.common.find_host_lun_id(volume, host,
                                                        extra_specs)
          self.assertEqual(ref_masked, maskedvols)
  
      def test_find_host_lun_id_not_attached(self):
          volume = self.data.test_volume
          extra_specs = self.data.extra_specs
          host = 'HostX'
          with mock.patch.object(self.rest, 'find_mv_connections_for_vol',
                                 return_value=None):
              maskedvols, __ = self.common.find_host_lun_id(
                  volume, host, extra_specs)
              self.assertEqual({}, maskedvols)
  
      @mock.patch.object(
          common.PowerMaxCommon, '_get_masking_views_from_volume',
          return_value=([tpd.PowerMaxData.masking_view_name_f],
                        [tpd.PowerMaxData.masking_view_name_f,
                         tpd.PowerMaxData.masking_view_name_Y_f]))
      def test_find_host_lun_id_multiattach(self, mock_mask):
          volume = self.data.test_volume
          extra_specs = self.data.extra_specs
          __, is_multiattach = self.common.find_host_lun_id(
              volume, 'HostX', extra_specs)
          self.assertTrue(is_multiattach)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_rdf_pair_volume',
                         return_value=tpd.PowerMaxData.rdf_group_vol_details)
      @mock.patch.object(rest.PowerMaxRest, 'get_volume',
                         return_value=tpd.PowerMaxData.volume_details[0])
      def test_find_host_lun_id_rep_extra_specs(self, mock_vol, mock_tgt):
          self.common.find_host_lun_id(
              self.data.test_volume, 'HostX',
              self.data.extra_specs, self.data.rep_extra_specs)
          mock_tgt.assert_called_once()
  
      @mock.patch.object(rest.PowerMaxRest, 'find_mv_connections_for_vol',
                         return_value='1')
      @mock.patch.object(common.PowerMaxCommon, '_get_masking_views_from_volume',
                         side_effect=[([], ['OS-HostX-I-PG-MV']),
                                      (['OS-HostX-I-PG-MV'],
                                       ['OS-HostX-I-PG-MV'])])
      @mock.patch.object(rest.PowerMaxRest, 'get_volume',
                         return_value=tpd.PowerMaxData.volume_details[0])
      def test_find_host_lun_id_backward_compatible(
              self, mock_vol, mock_mvs, mock_mv_conns):
          expected_dict = {'hostlunid': '1', 'maskingview': 'OS-HostX-I-PG-MV',
                           'array': '000197800123', 'device_id': '00001'}
          self.common.powermax_short_host_name_template = (
              'shortHostName[:7]finance')
          masked_vols, is_multiattach = self.common.find_host_lun_id(
              self.data.test_volume, 'HostX',
              self.data.extra_specs)
          self.assertEqual(expected_dict, masked_vols)
          self.assertFalse(is_multiattach)
          mock_mv_conns.assert_called_once()
  
      def test_get_masking_views_from_volume(self):
          array = self.data.array
          device_id = self.data.device_id
          host = 'HostX'
          ref_mv_list = [self.data.masking_view_name_f]
          maskingview_list, __ = self.common.get_masking_views_from_volume(
              array, self.data.test_volume, device_id, host)
          self.assertEqual(ref_mv_list, maskingview_list)
          # is metro
          with mock.patch.object(self.utils, 'is_metro_device',
                                 return_value=True):
              __, is_metro = self.common.get_masking_views_from_volume(
                  array, self.data.test_volume, device_id, host)
              self.assertTrue(is_metro)
  
      def test_get_masking_views_from_volume_wrong_host(self):
          array = self.data.array
          device_id = self.data.device_id
          host = 'DifferentHost'
          maskingview_list, __ = self.common.get_masking_views_from_volume(
              array, self.data.test_volume, device_id, host)
          self.assertEqual([], maskingview_list)
  
      def test_find_host_lun_id_no_host_check(self):
          volume = self.data.test_volume
          extra_specs = self.data.extra_specs
          host_lun = (self.data.maskingview[0]['maskingViewConnection'][0][
              'host_lun_address'])
          ref_masked = {'hostlunid': int(host_lun, 16),
                        'maskingview': self.data.masking_view_name_f,
                        'array': self.data.array,
                        'device_id': self.data.device_id}
          maskedvols, __ = self.common.find_host_lun_id(
              volume, None, extra_specs)
          self.assertEqual(ref_masked, maskedvols)
  
      def test_initial_setup_success(self):
          volume = self.data.test_volume
          ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          extra_specs = self.common._initial_setup(volume)
          self.assertEqual(ref_extra_specs, extra_specs)
  
      def test_initial_setup_failed(self):
          volume = self.data.test_volume
          with mock.patch.object(
                  self.common, 'get_attributes_from_cinder_config',
                  return_value=None):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common._initial_setup, volume)
  
      def test_initial_setup_success_specs_init_conn_call(self):
          volume = self.data.test_volume
          array_info = self.common.get_attributes_from_cinder_config()
          extra_specs, __ = self.common._set_config_file_and_get_extra_specs(
              volume)
          with mock.patch.object(
                  self.common, '_set_vmax_extra_specs',
                  side_effect=self.common._set_vmax_extra_specs) as mck_specs:
              self.common._initial_setup(volume, init_conn=True)
              mck_specs.assert_called_once_with(
                  extra_specs, array_info, True)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_rdf_pair_volume',
                         return_value=tpd.PowerMaxData.rdf_group_vol_details)
      def test_populate_masking_dict(self, mock_tgt):
          volume = self.data.test_volume
          connector = self.data.connector
          extra_specs = deepcopy(self.data.extra_specs)
          extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          extra_specs[utils.WORKLOAD] = self.data.workload
          ref_mv_dict = self.data.masking_view_dict
          self.common.next_gen = False
          self.common.powermax_port_group_name_template = 'portGroupName'
          extra_specs.pop(utils.IS_RE, None)
          masking_view_dict = self.common._populate_masking_dict(
              volume, connector, extra_specs)
          self.assertEqual(ref_mv_dict, masking_view_dict)
          # Metro volume, pass in rep_extra_specs and retrieve target device
          rep_extra_specs = deepcopy(self.data.rep_extra_specs)
          rep_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          self.common._populate_masking_dict(
              volume, connector, extra_specs, rep_extra_specs)
          mock_tgt.assert_called_once()
          # device_id is None
          with mock.patch.object(self.common, '_find_device_on_array',
                                 return_value=None):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common._populate_masking_dict,
                                volume, connector, extra_specs)
  
      def test_populate_masking_dict_no_slo(self):
          volume = self.data.test_volume
          connector = self.data.connector
          extra_specs = {'slo': None, 'workload': None, 'srp': self.data.srp,
                         'array': self.data.array,
                         utils.PORTGROUPNAME: self.data.port_group_name_f}
          ref_mv_dict = self.data.masking_view_dict_no_slo
          masking_view_dict = self.common._populate_masking_dict(
              volume, connector, extra_specs)
          self.assertEqual(ref_mv_dict, masking_view_dict)
  
      def test_populate_masking_dict_compr_disabled(self):
          volume = self.data.test_volume
          connector = self.data.connector
          extra_specs = deepcopy(self.data.extra_specs)
          extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          extra_specs[utils.DISABLECOMPRESSION] = "true"
          ref_mv_dict = self.data.masking_view_dict_compression_disabled
          extra_specs[utils.WORKLOAD] = self.data.workload
          masking_view_dict = self.common._populate_masking_dict(
              volume, connector, extra_specs)
          self.assertEqual(ref_mv_dict, masking_view_dict)
  
      def test_populate_masking_dict_next_gen(self):
          volume = self.data.test_volume
          connector = self.data.connector
          extra_specs = deepcopy(self.data.extra_specs)
          extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          self.common.next_gen = True
          masking_view_dict = self.common._populate_masking_dict(
              volume, connector, extra_specs)
          self.assertEqual('NONE', masking_view_dict[utils.WORKLOAD])
  
      @mock.patch.object(common.PowerMaxCommon, '_clone_check')
      def test_create_cloned_volume(self, mck_clone_chk):
          volume = self.data.test_clone_volume
          source_volume = self.data.test_volume
          extra_specs = self.data.extra_specs
          ref_response = (self.data.provider_location_clone, dict(), dict())
          clone_dict, rep_update, rep_info_dict = (
              self.common._create_cloned_volume(
                  volume, source_volume, extra_specs))
          self.assertEqual(ref_response, (clone_dict, rep_update, rep_info_dict))
  
      @mock.patch.object(common.PowerMaxCommon, '_clone_check')
      def test_create_cloned_volume_is_snapshot(self, mck_clone_chk):
          volume = self.data.test_snapshot
          source_volume = self.data.test_volume
          extra_specs = self.data.extra_specs
          ref_response = (self.data.snap_location, dict(), dict())
          clone_dict, rep_update, rep_info_dict = (
              self.common._create_cloned_volume(
                  volume, source_volume, extra_specs, True, False))
          self.assertEqual(ref_response, (clone_dict, rep_update, rep_info_dict))
  
      @mock.patch.object(common.PowerMaxCommon, '_clone_check')
      def test_create_cloned_volume_from_snapshot(self, mck_clone_chk):
          volume = self.data.test_clone_volume
          source_volume = self.data.test_snapshot
          extra_specs = self.data.extra_specs
          ref_response = (self.data.provider_location_snapshot, dict(), dict())
          clone_dict, rep_update, rep_info_dict = (
              self.common._create_cloned_volume(
                  volume, source_volume, extra_specs, False, True))
          self.assertEqual(ref_response, (clone_dict, rep_update, rep_info_dict))
  
      def test_create_cloned_volume_not_licenced(self):
          volume = self.data.test_clone_volume
          source_volume = self.data.test_volume
          extra_specs = self.data.extra_specs
          with mock.patch.object(self.rest, 'is_snapvx_licensed',
                                 return_value=False):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common._create_cloned_volume,
                                volume, source_volume, extra_specs)
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_find_device_on_array')
      def test_create_cloned_volume_not_licenced_2(self, mock_device):
          volume = self.data.test_clone_volume
          source_volume = self.data.test_volume
          extra_specs = self.data.extra_specs
          with mock.patch.object(self.rest, 'is_snapvx_licensed',
                                 return_value=False):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common._create_cloned_volume,
                                volume, source_volume, extra_specs,
                                False, False)
              mock_device.assert_not_called()
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_find_device_on_array',
                         return_value=None)
      @mock.patch.object(common.PowerMaxCommon,
                         '_clone_check')
      def test_create_cloned_volume_source_not_found(
              self, mock_check, mock_device):
          volume = self.data.test_clone_volume
          source_volume = self.data.test_volume
          extra_specs = self.data.extra_specs
          with mock.patch.object(self.rest, 'is_snapvx_licensed',
                                 return_value=True):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common._create_cloned_volume,
                                volume, source_volume, extra_specs,
                                False, False)
              mock_check.assert_not_called()
  
      def test_parse_snap_info_found(self):
          ref_device_id = self.data.device_id
          ref_snap_name = self.data.snap_location['snap_name']
          sourcedevice_id, foundsnap_name = self.common._parse_snap_info(
              self.data.array, self.data.test_snapshot)
          self.assertEqual(ref_device_id, sourcedevice_id)
          self.assertEqual(ref_snap_name, foundsnap_name)
  
      def test_parse_snap_info_not_found(self):
          ref_snap_name = None
          with mock.patch.object(self.rest, 'get_volume_snap',
                                 return_value=None):
              __, foundsnap_name = self.common._parse_snap_info(
                  self.data.array, self.data.test_snapshot)
              self.assertIsNone(ref_snap_name, foundsnap_name)
  
      def test_parse_snap_info_exception(self):
          with mock.patch.object(
                  self.rest, 'get_volume_snap',
                  side_effect=exception.VolumeBackendAPIException):
              __, foundsnap_name = self.common._parse_snap_info(
                  self.data.array, self.data.test_snapshot)
              self.assertIsNone(foundsnap_name)
  
      def test_parse_snap_info_provider_location_not_string(self):
          snapshot = fake_snapshot.fake_snapshot_obj(
              context='ctxt', provider_loaction={'not': 'string'})
          sourcedevice_id, foundsnap_name = self.common._parse_snap_info(
              self.data.array, snapshot)
          self.assertIsNone(foundsnap_name)
  
      def test_create_snapshot_success(self):
          array = self.data.array
          snapshot = self.data.test_snapshot
          source_device_id = self.data.device_id
          extra_specs = self.data.extra_specs
          ref_dict = {'snap_name': self.data.test_snapshot_snap_name,
                      'source_id': self.data.device_id}
          snap_dict = self.common._create_snapshot(
              array, snapshot, source_device_id, extra_specs)
          self.assertEqual(ref_dict, snap_dict)
  
      def test_create_snapshot_exception(self):
          array = self.data.array
          snapshot = self.data.test_snapshot
          source_device_id = self.data.device_id
          extra_specs = self.data.extra_specs
          with mock.patch.object(
                  self.provision, 'create_volume_snapvx',
                  side_effect=exception.VolumeBackendAPIException):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common._create_snapshot,
                                array, snapshot, source_device_id, extra_specs)
  
      @mock.patch.object(masking.PowerMaxMasking,
                         'remove_vol_from_storage_group')
      def test_delete_volume_from_srp(self, mock_rm):
          array = self.data.array
          device_id = self.data.device_id
          volume_name = self.data.test_volume.name
          ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          volume = self.data.test_volume
          with mock.patch.object(self.common, '_sync_check'):
              with mock.patch.object(
                      self.common, '_delete_from_srp') as mock_delete:
                  self.common._delete_volume(volume)
                  mock_delete.assert_called_once_with(
                      array, device_id, volume_name, ref_extra_specs)
  
      def test_delete_volume_not_found(self):
          volume = self.data.test_volume
          with mock.patch.object(self.common, '_find_device_on_array',
                                 return_value=None):
              with mock.patch.object(
                      self.common, '_delete_from_srp') as mock_delete:
                  self.common._delete_volume(volume)
                  mock_delete.assert_not_called()
  
      def test_create_volume_success(self):
          volume = self.data.test_volume
          volume_name = '1'
          volume_size = self.data.test_volume.size
          extra_specs = self.data.extra_specs
          ref_response = (self.data.provider_location, dict(), dict())
          with mock.patch.object(self.rest, 'get_volume',
                                 return_value=self.data.volume_details[0]):
              volume_dict, rep_update, rep_info_dict = (
                  self.common._create_volume(
                      volume, volume_name, volume_size, extra_specs))
          self.assertEqual(ref_response,
                           (volume_dict, rep_update, rep_info_dict))
  
      @mock.patch.object(rest.PowerMaxRest, 'find_volume_device_id',
                         return_value=tpd.PowerMaxData.device_id2)
      @mock.patch.object(
          common.PowerMaxCommon, '_create_non_replicated_volume',
          return_value=deepcopy(tpd.PowerMaxData.provider_location))
      @mock.patch.object(rest.PowerMaxRest, 'get_volume',
                         return_value=tpd.PowerMaxData.volume_details[0])
      def test_create_volume_update_returning_device_id(
              self, mck_get, mck_create, mck_find):
          volume = self.data.test_volume
          volume_name = '1'
          volume_size = self.data.test_volume.size
          extra_specs = self.data.extra_specs
          ref_response = (self.data.provider_location2, dict(), dict())
          volume_dict, rep_update, rep_info_dict = (
              self.common._create_volume(
                  volume, volume_name, volume_size, extra_specs))
          self.assertEqual(ref_response,
                           (volume_dict, rep_update, rep_info_dict))
  
      def test_create_volume_success_next_gen(self):
          volume = self.data.test_volume
          volume_name = '1'
          volume_size = self.data.test_volume.size
          extra_specs = self.data.extra_specs
          self.common.next_gen = True
          with mock.patch.object(
                  self.utils, 'is_compression_disabled', return_value=True):
              with mock.patch.object(
                      self.rest, 'get_array_model_info',
                      return_value=('PowerMax 2000', True)):
                  with mock.patch.object(
                          self.masking,
                          'get_or_create_default_storage_group') as mock_get:
                      self.common._create_volume(
                          volume, volume_name, volume_size, extra_specs)
                      mock_get.assert_called_once_with(
                          extra_specs['array'], extra_specs[utils.SRP],
                          extra_specs[utils.SLO], 'NONE', extra_specs, True,
                          False, None)
  
      @mock.patch.object(provision.PowerMaxProvision, 'create_volume_from_sg',
                         side_effect=exception.VolumeBackendAPIException(''))
      @mock.patch.object(common.PowerMaxCommon,
                         '_cleanup_non_rdf_volume_create_post_failure')
      @mock.patch.object(rest.PowerMaxRest, 'delete_storage_group')
      def test_create_volume_failed(self, mck_del, mck_cleanup, mck_create):
          volume = self.data.test_volume
          volume_name = self.data.test_volume.name
          volume_size = self.data.test_volume.size
          extra_specs = self.data.extra_specs
          dev1 = self.data.device_id
          dev2 = self.data.device_id2
          with mock.patch.object(
                  self.rest, 'get_volumes_in_storage_group',
                  side_effect=[[dev1], [dev1, dev2]]):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common._create_volume,
                                volume, volume_name, volume_size,
                                extra_specs)
              mck_cleanup.assert_called_once_with(
                  volume, volume_name, extra_specs, [dev2])
          # path 2: no new volumes created
          with mock.patch.object(
                  self.rest, 'get_volumes_in_storage_group',
                  side_effect=[[], []]):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common._create_volume,
                                volume, volume_name, volume_size,
                                extra_specs)
              mck_del.assert_called_once()
  
      @mock.patch.object(common.PowerMaxCommon, 'cleanup_rdf_device_pair')
      @mock.patch.object(
          rest.PowerMaxRest, 'is_vol_in_rep_session', return_value=('', '', [
              {utils.RDF_GROUP_NO: tpd.PowerMaxData.rdf_group_no_1}]))
      @mock.patch.object(rest.PowerMaxRest, 'srdf_resume_replication')
      @mock.patch.object(utils.PowerMaxUtils, 'get_default_storage_group_name',
                         return_value=tpd.PowerMaxData.storagegroup_name_f)
      @mock.patch.object(common.PowerMaxCommon, 'prepare_replication_details',
                         return_value=('', tpd.PowerMaxData.rep_extra_specs,
                                       '', '',))
      def test_cleanup_rdf_volume_create_post_failure_sync(
              self, mck_prep, mck_sg, mck_resume, mck_sess, mck_clean):
          array = self.data.array
          volume = self.data.test_volume
          volume_name = self.data.test_volume.name
          extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
          extra_specs[utils.REP_CONFIG] = self.data.rep_config_sync
          extra_specs['rep_mode'] = utils.REP_SYNC
          devices = [self.data.device_id]
          self.common._cleanup_rdf_volume_create_post_failure(
              volume, volume_name, extra_specs, devices)
          mck_prep.assert_called_once_with(extra_specs)
          mck_sg.assert_called_once_with(
              extra_specs['srp'], extra_specs['slo'], extra_specs['workload'],
              False, True, extra_specs['rep_mode'])
          mck_resume.assert_called_once_with(
              array, self.data.storagegroup_name_f, self.data.rdf_group_no_1,
              self.data.rep_extra_specs)
          mck_sess.assert_called_once_with(array, self.data.device_id)
          mck_clean.assert_called_once_with(
              array, self.data.rdf_group_no_1, self.data.device_id, extra_specs)
  
      @mock.patch.object(common.PowerMaxCommon, 'cleanup_rdf_device_pair')
      @mock.patch.object(
          rest.PowerMaxRest, 'is_vol_in_rep_session', return_value=('', '', [
              {utils.RDF_GROUP_NO: tpd.PowerMaxData.rdf_group_no_1}]))
      @mock.patch.object(rest.PowerMaxRest, 'srdf_resume_replication')
      @mock.patch.object(utils.PowerMaxUtils, 'get_rdf_management_group_name',
                         return_value=tpd.PowerMaxData.storagegroup_name_f)
      @mock.patch.object(common.PowerMaxCommon, 'prepare_replication_details',
                         return_value=('', tpd.PowerMaxData.rep_extra_specs,
                                       '', '',))
      def test_cleanup_rdf_volume_create_post_failure_non_sync(
              self, mck_prep, mck_mgmt, mck_resume, mck_sess, mck_clean):
          array = self.data.array
          volume = self.data.test_volume
          volume_name = self.data.test_volume.name
          extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
          extra_specs[utils.REP_CONFIG] = self.data.rep_config_async
          extra_specs['rep_mode'] = utils.REP_ASYNC
          devices = [self.data.device_id]
          self.common._cleanup_rdf_volume_create_post_failure(
              volume, volume_name, extra_specs, devices)
          mck_prep.assert_called_once_with(extra_specs)
          mck_mgmt.assert_called_once_with(extra_specs[utils.REP_CONFIG])
          mck_resume.assert_called_once_with(
              array, self.data.storagegroup_name_f, self.data.rdf_group_no_1,
              self.data.rep_extra_specs)
          mck_sess.assert_called_once_with(array, self.data.device_id)
          mck_clean.assert_called_once_with(
              array, self.data.rdf_group_no_1, self.data.device_id, extra_specs)
  
      @mock.patch.object(common.PowerMaxCommon, '_delete_from_srp')
      @mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=('', '', False))
      @mock.patch.object(rest.PowerMaxRest, 'srdf_resume_replication')
      @mock.patch.object(utils.PowerMaxUtils, 'get_rdf_management_group_name',
                         return_value=tpd.PowerMaxData.storagegroup_name_f)
      @mock.patch.object(common.PowerMaxCommon, 'prepare_replication_details',
                         return_value=('', tpd.PowerMaxData.rep_extra_specs,
                                       '', '',))
      def test_cleanup_rdf_volume_create_post_failure_pre_rdf_establish(
              self, mck_prep, mck_mgmt, mck_resume, mck_sess, mck_rem, mck_del):
          array = self.data.array
          volume = self.data.test_volume
          volume_name = self.data.test_volume.name
          extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
          extra_specs[utils.REP_CONFIG] = self.data.rep_config_sync
          extra_specs['rep_mode'] = utils.REP_ASYNC
          devices = [self.data.device_id]
          self.common._cleanup_rdf_volume_create_post_failure(
              volume, volume_name, extra_specs, devices)
          mck_prep.assert_called_once_with(extra_specs)
          mck_mgmt.assert_called_once_with(extra_specs[utils.REP_CONFIG])
          mck_resume.assert_called_once_with(
              array, self.data.storagegroup_name_f, self.data.rdf_group_no_1,
              self.data.rep_extra_specs)
          mck_sess.assert_called_once_with(array, self.data.device_id)
          mck_rem.assert_called_once_with(array, volume, self.data.device_id,
                                          volume_name, extra_specs, False)
          mck_del.assert_called_once_with(array, self.data.device_id,
                                          volume_name, extra_specs)
  
      @mock.patch.object(common.PowerMaxCommon, '_delete_from_srp')
      @mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
      def test_cleanup_non_rdf_volume_create_post_failure(
              self, mck_remove, mck_del):
          array = self.data.array
          volume = self.data.test_volume
          volume_name = self.data.test_volume.name
          extra_specs = self.data.extra_specs
          devices = [self.data.device_id]
          self.common._cleanup_non_rdf_volume_create_post_failure(
              volume, volume_name, extra_specs, devices)
          mck_remove.assert_called_once_with(
              array, volume, self.data.device_id, volume_name, extra_specs,
              False)
          mck_del.assert_called_once_with(
              array, self.data.device_id, volume_name, extra_specs)
  
      def test_create_volume_incorrect_slo(self):
          volume = self.data.test_volume
          volume_name = self.data.test_volume.name
          volume_size = self.data.test_volume.size
          extra_specs = {'slo': 'Diamondz',
                         'workload': 'DSSSS',
                         'srp': self.data.srp,
                         'array': self.data.array}
          self.assertRaises(
              exception.VolumeBackendAPIException,
              self.common._create_volume,
              volume, volume_name, volume_size, extra_specs)
  
      def test_set_vmax_extra_specs(self):
          srp_record = self.common.get_attributes_from_cinder_config()
          extra_specs = self.common._set_vmax_extra_specs(
              self.data.vol_type_extra_specs, srp_record)
          ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          self.assertEqual(ref_extra_specs, extra_specs)
  
      def test_set_vmax_extra_specs_no_srp_name(self):
          srp_record = self.common.get_attributes_from_cinder_config()
          with mock.patch.object(self.rest, 'get_slo_list',
                                 return_value=[]):
              extra_specs = self.common._set_vmax_extra_specs({}, srp_record)
              self.assertIsNone(extra_specs['slo'])
  
      def test_set_vmax_extra_specs_compr_disabled(self):
          with mock.patch.object(self.rest, 'is_compression_capable',
                                 return_value=True):
              srp_record = self.common.get_attributes_from_cinder_config()
              extra_specs = self.common._set_vmax_extra_specs(
                  self.data.vol_type_extra_specs_compr_disabled, srp_record)
              ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
              ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
              ref_extra_specs[utils.DISABLECOMPRESSION] = "true"
              self.assertEqual(ref_extra_specs, extra_specs)
  
      def test_set_vmax_extra_specs_compr_disabled_not_compr_capable(self):
          srp_record = self.common.get_attributes_from_cinder_config()
          extra_specs = self.common._set_vmax_extra_specs(
              self.data.vol_type_extra_specs_compr_disabled, srp_record)
          ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          self.assertEqual(ref_extra_specs, extra_specs)
  
      def test_set_vmax_extra_specs_portgroup_as_spec(self):
          srp_record = self.common.get_attributes_from_cinder_config()
          extra_specs = self.common._set_vmax_extra_specs(
              {utils.PORTGROUPNAME: 'extra_spec_pg'}, srp_record)
          self.assertEqual('extra_spec_pg', extra_specs[utils.PORTGROUPNAME])
  
      def test_set_vmax_extra_specs_no_portgroup_set(self):
          srp_record = {
              'srpName': 'SRP_1', 'RestServerIp': '1.1.1.1',
              'RestPassword': 'smc', 'SSLCert': None, 'RestServerPort': 8443,
              'SSLVerify': False, 'RestUserName': 'smc',
              'SerialNumber': '000197800123'}
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common._set_vmax_extra_specs,
                            {}, srp_record)
  
      def test_set_vmax_extra_specs_next_gen(self):
          srp_record = self.common.get_attributes_from_cinder_config()
          self.common.next_gen = True
          extra_specs = self.common._set_vmax_extra_specs(
              self.data.vol_type_extra_specs, srp_record)
          ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          self.assertEqual('NONE', extra_specs[utils.WORKLOAD])
  
      def test_set_vmax_extra_specs_tags_not_set(self):
          srp_record = self.common.get_attributes_from_cinder_config()
          extra_specs = self.common._set_vmax_extra_specs(
              self.data.vol_type_extra_specs, srp_record)
          self.assertTrue('storagetype:storagegrouptags' not in extra_specs)
  
      def test_set_vmax_extra_specs_tags_set_correctly(self):
          srp_record = self.common.get_attributes_from_cinder_config()
          extra_specs = self.common._set_vmax_extra_specs(
              self.data.vol_type_extra_specs_tags, srp_record)
          self.assertEqual(
              self.data.vol_type_extra_specs_tags[utils.STORAGE_GROUP_TAGS],
              extra_specs[utils.STORAGE_GROUP_TAGS])
  
      def test_set_vmax_extra_specs_tags_set_incorrectly(self):
          srp_record = self.common.get_attributes_from_cinder_config()
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common._set_vmax_extra_specs,
                            self.data.vol_type_extra_specs_tags_bad, srp_record)
  
      def test_set_vmax_extra_specs_pg_specs_init_conn(self):
          pool_record = self.common.get_attributes_from_cinder_config()
          with mock.patch.object(
                  self.common, '_select_port_group_for_extra_specs',
                  side_effect=(
                      self.common._select_port_group_for_extra_specs)) as mck_s:
              self.common._set_vmax_extra_specs(
                  self.data.vol_type_extra_specs, pool_record, init_conn=True)
              mck_s.assert_called_once_with(
                  self.data.vol_type_extra_specs, pool_record, True)
  
      def test_delete_volume_from_srp_success(self):
          array = self.data.array
          device_id = self.data.device_id
          volume_name = self.data.test_volume.name
          extra_specs = self.data.extra_specs
          with mock.patch.object(
                  self.provision, 'delete_volume_from_srp') as mock_del:
              self.common._delete_from_srp(array, device_id, volume_name,
                                           extra_specs)
              mock_del.assert_called_once_with(array, device_id, volume_name)
  
      def test_delete_volume_from_srp_failed(self):
          self.mock_object(time, 'sleep')
          array = self.data.array
          device_id = self.data.failed_resource
          volume_name = self.data.test_volume.name
          extra_specs = self.data.extra_specs
          with mock.patch.object(
                  self.masking,
                  'add_volume_to_default_storage_group') as mock_add:
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common._delete_from_srp, array,
                                device_id, volume_name, extra_specs)
              mock_add.assert_not_called()
  
      @mock.patch.object(utils.PowerMaxUtils, 'is_volume_failed_over',
                         side_effect=[True, False])
      @mock.patch.object(common.PowerMaxCommon, '_get_replication_extra_specs',
                         return_value=tpd.PowerMaxData.rep_extra_specs)
      def test_get_target_wwns_from_masking_view(self, mock_rep_specs, mock_fo):
          ref_wwns = [self.data.wwnn1]
          for x in range(0, 2):
              target_wwns = self.common._get_target_wwns_from_masking_view(
                  self.data.device_id, self.data.connector['host'],
                  self.data.extra_specs)
              self.assertEqual(ref_wwns, target_wwns)
  
      def test_get_target_wwns_from_masking_view_no_mv(self):
          with mock.patch.object(self.common, '_get_masking_views_from_volume',
                                 return_value=([], None)):
              target_wwns = self.common._get_target_wwns_from_masking_view(
                  self.data.device_id, self.data.connector['host'],
                  self.data.extra_specs)
              self.assertEqual([], target_wwns)
  
      @mock.patch.object(common.PowerMaxCommon, '_get_replication_extra_specs',
                         return_value=tpd.PowerMaxData.rep_extra_specs)
      @mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
                         return_value=('1', tpd.PowerMaxData.remote_array))
      @mock.patch.object(rest.PowerMaxRest, 'get_rdf_pair_volume',
                         return_value=tpd.PowerMaxData.rdf_group_vol_details)
      @mock.patch.object(
          common.PowerMaxCommon, '_get_target_wwns_from_masking_view',
          return_value=[tpd.PowerMaxData.wwnn1])
      def test_get_target_wwns(
              self, mck_wwns, mock_tgt, mock_rdf_grp, mock_specs):
          __, metro_wwns = self.common.get_target_wwns_from_masking_view(
              self.data.test_volume, self.data.connector)
          self.assertEqual([], metro_wwns)
          # Is metro volume
          with mock.patch.object(common.PowerMaxCommon, '_initial_setup',
                                 return_value=self.data.ex_specs_rep_config):
              __, metro_wwns = self.common.get_target_wwns_from_masking_view(
                  self.data.test_volume, self.data.connector)
              self.assertEqual([self.data.wwnn1], metro_wwns)
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_get_target_wwns_from_masking_view')
      @mock.patch.object(utils.PowerMaxUtils, 'get_host_name_label',
                         return_value = 'my_short_h94485')
      @mock.patch.object(utils.PowerMaxUtils, 'is_replication_enabled',
                         return_value=False)
      def test_get_target_wwns_host_override(
              self, mock_rep_check, mock_label, mock_mv):
          host_record = {'host': 'my_short_host_name'}
          connector = deepcopy(self.data.connector)
          connector.update(host_record)
          extra_specs = {'pool_name': 'Diamond+DSS+SRP_1+000197800123',
                         'srp': 'SRP_1', 'array': '000197800123',
                         'storagetype:portgroupname': 'OS-fibre-PG',
                         'interval': 1, 'retries': 1, 'slo': 'Diamond',
                         'workload': 'DSS'}
          host_template = 'shortHostName[:10]uuid[:5]'
          self.common.powermax_short_host_name_template = host_template
          self.common.get_target_wwns_from_masking_view(
              self.data.test_volume, connector)
          mock_label.assert_called_once_with(
              connector['host'], host_template)
          mock_mv.assert_called_once_with(
              self.data.device_id, 'my_short_h94485', extra_specs)
  
      def test_get_port_group_from_masking_view(self):
          array = self.data.array
          maskingview_name = self.data.masking_view_name_f
  
          with mock.patch.object(self.rest,
                                 'get_element_from_masking_view') as mock_get:
              self.common.get_port_group_from_masking_view(
                  array, maskingview_name)
              mock_get.assert_called_once_with(
                  array, maskingview_name, portgroup=True)
  
      def test_get_initiator_group_from_masking_view(self):
          array = self.data.array
          maskingview_name = self.data.masking_view_name_f
          with mock.patch.object(
                  self.rest, 'get_element_from_masking_view') as mock_get:
              self.common.get_initiator_group_from_masking_view(
                  array, maskingview_name)
              mock_get.assert_called_once_with(
                  array, maskingview_name, host=True)
  
      def test_get_common_masking_views(self):
          array = self.data.array
          portgroup_name = self.data.port_group_name_f
          initiator_group_name = self.data.initiatorgroup_name_f
          with mock.patch.object(
                  self.rest, 'get_common_masking_views') as mock_get:
              self.common.get_common_masking_views(
                  array, portgroup_name, initiator_group_name)
              mock_get.assert_called_once_with(
                  array, portgroup_name, initiator_group_name)
  
      def test_get_iscsi_ip_iqn_port(self):
          phys_port = '%(dir)s:%(port)s' % {'dir': self.data.iscsi_dir,
                                            'port': self.data.iscsi_port}
          ref_ip_iqn = [{'iqn': self.data.initiator,
                         'ip': self.data.ip,
                         'physical_port': phys_port}]
  
          director = self.data.portgroup[1]['symmetrixPortKey'][0]['directorId']
          port = self.data.portgroup[1]['symmetrixPortKey'][0]['portId']
          dirport = "%s:%s" % (director, port)
  
          ip_iqn_list = self.common._get_iscsi_ip_iqn_port(self.data.array,
                                                           dirport)
          self.assertEqual(ref_ip_iqn, ip_iqn_list)
  
      def test_find_ip_and_iqns(self):
          ref_ip_iqn = [{'iqn': self.data.initiator,
                         'ip': self.data.ip,
                         'physical_port': self.data.iscsi_dir_port}]
          ip_iqn_list = self.common._find_ip_and_iqns(
              self.data.array, self.data.port_group_name_i)
          self.assertEqual(ref_ip_iqn, ip_iqn_list)
  
      def test_create_replica_snap_name(self):
          array = self.data.array
          clone_volume = self.data.test_clone_volume
          source_device_id = self.data.device_id
          snap_name = self.data.snap_location['snap_name']
          ref_response = (self.data.provider_location_snapshot, dict(), dict())
          clone_dict, rep_update, rep_info_dict = self.common._create_replica(
              array, clone_volume, source_device_id,
              self.data.extra_specs, snap_name)
          self.assertEqual(ref_response, (clone_dict, rep_update, rep_info_dict))
  
      def test_create_replica_no_snap_name(self):
          array = self.data.array
          clone_volume = self.data.test_clone_volume
          source_device_id = self.data.device_id
          snap_name = "temp-" + source_device_id + "-snapshot_for_clone"
          ref_response = (self.data.provider_location_clone, dict(), dict())
          with mock.patch.object(
                  self.utils, 'get_temp_snap_name',
                  return_value=snap_name) as mock_get_snap:
              clone_dict, rep_update, rep_info_dict = (
                  self.common._create_replica(
                      array, clone_volume, source_device_id,
                      self.data.extra_specs))
              self.assertEqual(ref_response,
                               (clone_dict, rep_update, rep_info_dict))
              mock_get_snap.assert_called_once_with(source_device_id)
  
      def test_create_replica_failed_cleanup_target(self):
          array = self.data.array
          clone_volume = self.data.test_clone_volume
          device_id = self.data.device_id
          snap_name = self.data.failed_resource
          clone_name = 'OS-' + clone_volume.id
          extra_specs = self.data.extra_specs
          with mock.patch.object(
                  self.common, '_cleanup_target') as mock_cleanup:
              self.assertRaises(
                  exception.VolumeBackendAPIException,
                  self.common._create_replica, array, clone_volume, device_id,
                  self.data.extra_specs, snap_name)
              mock_cleanup.assert_called_once_with(
                  array, device_id, device_id, clone_name, snap_name,
                  extra_specs, target_volume=clone_volume)
  
      def test_create_replica_failed_no_target(self):
          array = self.data.array
          clone_volume = self.data.test_clone_volume
          source_device_id = self.data.device_id
          snap_name = self.data.failed_resource
          with mock.patch.object(self.common, '_create_volume',
                                 return_value=({'device_id': None}, {}, {})):
              with mock.patch.object(
                      self.common, '_cleanup_target') as mock_cleanup:
                  self.assertRaises(
                      exception.VolumeBackendAPIException,
                      self.common._create_replica, array, clone_volume,
                      source_device_id, self.data.extra_specs, snap_name)
                  mock_cleanup.assert_not_called()
  
      @mock.patch.object(
          utils.PowerMaxUtils,
          'compare_cylinders',
          side_effect=exception.VolumeBackendAPIException)
      def test_create_replica_cylinder_mismatch(self, mock_cyl):
          array = self.data.array
          clone_volume = self.data.test_clone_volume
          source_device_id = self.data.device_id
          snap_name = self.data.snap_location['snap_name']
          clone_name = 'OS-' + clone_volume.id
          with mock.patch.object(
                  self.common, '_cleanup_target') as mock_cleanup:
              self.assertRaises(                     # noqa: H202
                  Exception, self.common._create_replica, array,
                  clone_volume, source_device_id,
                  self.data.extra_specs, snap_name)  # noqa: ignore=H202
              mock_cleanup.assert_called_once_with(
                  array, source_device_id, source_device_id,
                  clone_name, snap_name, self.data.extra_specs,
                  target_volume=clone_volume)
  
      @mock.patch.object(
          masking.PowerMaxMasking,
          'remove_and_reset_members')
      def test_cleanup_target_sync_present(self, mock_remove):
          array = self.data.array
          clone_volume = self.data.test_clone_volume
          source_device_id = self.data.device_id
          target_device_id = self.data.device_id2
          snap_name = self.data.failed_resource
          clone_name = clone_volume.name
          extra_specs = self.data.extra_specs
          generation = 0
          with mock.patch.object(self.rest, 'get_sync_session',
                                 return_value='session'):
              with mock.patch.object(
                      self.provision, 'unlink_snapvx_tgt_volume') as mock_break:
                  self.common._cleanup_target(
                      array, target_device_id, source_device_id,
                      clone_name, snap_name, extra_specs)
                  mock_break.assert_called_with(
                      array, target_device_id, source_device_id,
                      snap_name, extra_specs, generation)
  
      @mock.patch.object(masking.PowerMaxMasking, 'remove_volume_from_sg')
      def test_cleanup_target_no_sync(self, mock_remove):
          array = self.data.array
          clone_volume = self.data.test_clone_volume
          source_device_id = self.data.device_id
          target_device_id = self.data.device_id2
          snap_name = self.data.failed_resource
          clone_name = clone_volume.name
          extra_specs = self.data.extra_specs
          with mock.patch.object(self.rest, 'get_sync_session',
                                 return_value=None):
              with mock.patch.object(
                      self.common, '_delete_from_srp') as mock_delete:
                  self.common._cleanup_target(
                      array, target_device_id, source_device_id,
                      clone_name, snap_name, extra_specs)
                  mock_delete.assert_called_once_with(
                      array, target_device_id, clone_name,
                      extra_specs)
  
      @mock.patch.object(
          common.PowerMaxCommon, 'get_volume_metadata',
          return_value={'device-meta-key-1': 'device-meta-value-1',
                        'device-meta-key-2': 'device-meta-value-2'})
      def test_manage_existing_success(self, mck_meta):
          external_ref = {u'source-name': u'00002'}
          provider_location = {'device_id': u'00002', 'array': u'000197800123'}
          ref_update = {'provider_location': six.text_type(provider_location),
                        'metadata': {'device-meta-key-1': 'device-meta-value-1',
                                     'device-meta-key-2': 'device-meta-value-2',
                                     'user-meta-key-1': 'user-meta-value-1',
                                     'user-meta-key-2': 'user-meta-value-2'}}
          volume = deepcopy(self.data.test_volume)
          volume.metadata = {'user-meta-key-1': 'user-meta-value-1',
                             'user-meta-key-2': 'user-meta-value-2'}
          with mock.patch.object(
                  self.common, '_check_lun_valid_for_cinder_management',
                  return_value=('vol1', 'test_sg')):
              model_update = self.common.manage_existing(volume, external_ref)
              self.assertEqual(ref_update, model_update)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_volume_list',
                         return_value=[tpd.PowerMaxData.device_id3])
      @mock.patch.object(
          rest.PowerMaxRest, 'get_masking_views_from_storage_group',
          return_value=None)
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(False, False, None))
      def test_check_lun_valid_for_cinder_management(
              self, mock_rep, mock_mv, mock_list):
          external_ref = {u'source-name': u'00003'}
          vol, source_sg = self.common._check_lun_valid_for_cinder_management(
              self.data.array, self.data.device_id3,
              self.data.test_volume.id, external_ref)
          self.assertEqual(vol, '123')
          self.assertIsNone(source_sg)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_volume_list',
                         return_value=[tpd.PowerMaxData.device_id4])
      @mock.patch.object(
          rest.PowerMaxRest, 'get_masking_views_from_storage_group',
          return_value=None)
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(False, False, None))
      def test_check_lun_valid_for_cinder_management_multiple_sg_exception(
              self, mock_rep, mock_mv, mock_list):
          external_ref = {u'source-name': u'00004'}
          self.assertRaises(
              exception.ManageExistingInvalidReference,
              self.common._check_lun_valid_for_cinder_management,
              self.data.array, self.data.device_id4,
              self.data.test_volume.id, external_ref)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_volume_list',
                         return_value=[tpd.PowerMaxData.device_id3])
      @mock.patch.object(rest.PowerMaxRest, 'get_volume',
                         side_effect=[None,
                                      tpd.PowerMaxData.volume_details[2],
                                      tpd.PowerMaxData.volume_details[2],
                                      tpd.PowerMaxData.volume_details[1]])
      @mock.patch.object(
          rest.PowerMaxRest, 'get_masking_views_from_storage_group',
          side_effect=[tpd.PowerMaxData.sg_details[1]['maskingview'],
                       None])
      @mock.patch.object(
          rest.PowerMaxRest, 'get_storage_groups_from_volume',
          return_value=([tpd.PowerMaxData.defaultstoragegroup_name]))
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         side_effect=[(True, False, []), (False, False, None)])
      def test_check_lun_valid_for_cinder_management_exception(
              self, mock_rep, mock_sg, mock_mvs, mock_get_vol, mock_list):
          external_ref = {u'source-name': u'00003'}
          for x in range(0, 3):
              self.assertRaises(
                  exception.ManageExistingInvalidReference,
                  self.common._check_lun_valid_for_cinder_management,
                  self.data.array, self.data.device_id3,
                  self.data.test_volume.id, external_ref)
          self.assertRaises(exception.ManageExistingAlreadyManaged,
                            self.common._check_lun_valid_for_cinder_management,
                            self.data.array, self.data.device_id3,
                            self.data.test_volume.id, external_ref)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_volume_list',
                         return_value=[tpd.PowerMaxData.device_id])
      @mock.patch.object(
          rest.PowerMaxRest, 'get_masking_views_from_storage_group',
          return_value=None)
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(False, False, None))
      def test_check_lun_valid_for_cinder_management_non_FBA(
              self, mock_rep, mock_mv, mock_list):
          external_ref = {u'source-name': u'00004'}
          self.assertRaises(
              exception.ManageExistingVolumeTypeMismatch,
              self.common._check_lun_valid_for_cinder_management,
              self.data.array, self.data.device_id4,
              self.data.test_volume.id, external_ref)
  
      def test_manage_existing_get_size(self):
          external_ref = {u'source-name': u'00001'}
          size = self.common.manage_existing_get_size(
              self.data.test_volume, external_ref)
          self.assertEqual(2, size)
  
      def test_manage_existing_get_size_exception(self):
          external_ref = {u'source-name': u'00001'}
          with mock.patch.object(self.rest, 'get_size_of_device_on_array',
                                 return_value=3.5):
              self.assertRaises(exception.ManageExistingInvalidReference,
                                self.common.manage_existing_get_size,
                                self.data.test_volume, external_ref)
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_remove_vol_and_cleanup_replication')
      @mock.patch.object(common.PowerMaxCommon, '_clone_check')
      def test_unmanage_success(self, mck_clone, mock_rm):
          volume = self.data.test_volume
          with mock.patch.object(self.rest, 'rename_volume') as mock_rename:
              self.common.unmanage(volume)
              mock_rename.assert_called_once_with(
                  self.data.array, self.data.device_id,
                  self.data.test_volume.id)
          # Test for success when create storage group fails
          with mock.patch.object(self.rest, 'rename_volume') as mock_rename:
              with mock.patch.object(
                      self.provision, 'create_storage_group',
                      side_effect=exception.VolumeBackendAPIException):
                  self.common.unmanage(volume)
                  mock_rename.assert_called_once_with(
                      self.data.array, self.data.device_id,
                      self.data.test_volume.id)
  
      def test_unmanage_device_not_found(self):
          volume = self.data.test_volume
          with mock.patch.object(self.common, '_find_device_on_array',
                                 return_value=None):
              with mock.patch.object(self.rest, 'rename_volume') as mock_rename:
                  self.common.unmanage(volume)
                  mock_rename.assert_not_called()
  
      @mock.patch.object(common.PowerMaxCommon, '_slo_workload_migration')
      def test_retype(self, mock_migrate):
          device_id = self.data.device_id
          volume_name = self.data.test_volume.name
          extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
          volume = self.data.test_volume
          new_type = {'extra_specs': {}}
          host = {'host': self.data.new_host}
          self.common.retype(volume, new_type, host)
          mock_migrate.assert_called_once_with(
              device_id, volume, host, volume_name, new_type, extra_specs)
          with mock.patch.object(
                  self.common, '_find_device_on_array', return_value=None):
              self.assertFalse(self.common.retype(volume, new_type, host))
  
      def test_retype_attached_vol(self):
          host = {'host': self.data.new_host}
          new_type = {'extra_specs': {}}
          with mock.patch.object(
                  self.common, '_find_device_on_array', return_value=True):
              with mock.patch.object(self.common,
                                     '_slo_workload_migration') as mock_retype:
                  self.common.retype(self.data.test_attached_volume,
                                     new_type, host)
                  mock_retype.assert_called_once()
  
      @mock.patch.object(utils.PowerMaxUtils, 'is_retype_supported',
                         return_value=False)
      def test_retype_not_supported(self, mck_retype):
          volume = self.data.test_volume
          new_type = {'extra_specs': self.data.rep_extra_specs}
          host = self.data.new_host
          self.assertFalse(self.common.retype(volume, new_type, host))
  
      def test_slo_workload_migration_valid(self):
          device_id = self.data.device_id
          volume_name = self.data.test_volume.name
          extra_specs = self.data.extra_specs
          new_type = {'extra_specs': self.data.vol_type_extra_specs}
          volume = self.data.test_volume
          host = {'host': self.data.new_host}
          with mock.patch.object(self.common, '_migrate_volume') as mock_migrate:
              self.common._slo_workload_migration(
                  device_id, volume, host, volume_name, new_type, extra_specs)
              mock_migrate.assert_called_once_with(
                  extra_specs[utils.ARRAY], volume, device_id,
                  extra_specs[utils.SRP], 'Silver',
                  'OLTP', volume_name, new_type, extra_specs)
  
      def test_slo_workload_migration_not_valid(self):
          device_id = self.data.device_id
          volume_name = self.data.test_volume.name
          extra_specs = self.data.extra_specs
          volume = self.data.test_volume
          new_type = {'extra_specs': self.data.vol_type_extra_specs}
          host = {'host': self.data.new_host}
          with mock.patch.object(
                  self.common, '_is_valid_for_storage_assisted_migration',
                  return_value=(False, 'Silver', 'OLTP')):
              migrate_status = self.common._slo_workload_migration(
                  device_id, volume, host, volume_name, new_type, extra_specs)
              self.assertFalse(migrate_status)
  
      def test_slo_workload_migration_same_hosts(self):
          device_id = self.data.device_id
          volume_name = self.data.test_volume.name
          extra_specs = self.data.extra_specs
          volume = self.data.test_volume
          host = {'host': self.data.fake_host}
          new_type = {'extra_specs': {'slo': 'Bronze'}}
          migrate_status = self.common._slo_workload_migration(
              device_id, volume, host, volume_name, new_type, extra_specs)
          self.assertFalse(migrate_status)
  
      def test_slo_workload_migration_same_host_change_compression(self):
          device_id = self.data.device_id
          volume_name = self.data.test_volume.name
          extra_specs = self.data.extra_specs
          volume = self.data.test_volume
          host = {'host': self.data.fake_host}
          new_type = {'extra_specs': {utils.DISABLECOMPRESSION: "true"}}
  
          with mock.patch.object(
                  self.common, '_is_valid_for_storage_assisted_migration',
                  return_value=(True, self.data.slo, self.data.workload)):
              with mock.patch.object(
                      self.common, '_migrate_volume') as mock_migrate:
                  migrate_status = self.common._slo_workload_migration(
                      device_id, volume, host, volume_name, new_type,
                      extra_specs)
                  self.assertTrue(bool(migrate_status))
                  mock_migrate.assert_called_once_with(
                      extra_specs[utils.ARRAY], volume, device_id,
                      extra_specs[utils.SRP], self.data.slo,
                      self.data.workload, volume_name, new_type, extra_specs)
  
      @mock.patch.object(
          common.PowerMaxCommon, 'get_volume_metadata', return_value='')
      @mock.patch.object(
          common.PowerMaxCommon, '_retype_volume',
          return_value=(True, tpd.PowerMaxData.defaultstoragegroup_name))
      def test_migrate_volume_success_no_rep(self, mck_retype, mck_get):
          array_id = self.data.array
          volume = self.data.test_volume
          device_id = self.data.device_id
          srp = self.data.srp
          target_slo = self.data.slo_silver
          target_workload = self.data.workload
          volume_name = volume.name
          new_type = {'extra_specs': {}}
          extra_specs = self.data.extra_specs
  
          target_extra_specs = {
              utils.SRP: srp, utils.ARRAY: array_id, utils.SLO: target_slo,
              utils.WORKLOAD: target_workload,
              utils.INTERVAL: extra_specs[utils.INTERVAL],
              utils.RETRIES: extra_specs[utils.RETRIES],
              utils.DISABLECOMPRESSION: False}
  
          success, model_update = self.common._migrate_volume(
              array_id, volume, device_id, srp, target_slo, target_workload,
              volume_name, new_type, extra_specs)
          mck_retype.assert_called_once_with(
              array_id, srp, device_id, volume, volume_name, extra_specs,
              target_slo, target_workload, target_extra_specs)
          self.assertTrue(success)
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_post_retype_srdf_protect_storage_group',
                         return_value=(True, True, True))
      @mock.patch.object(utils.PowerMaxUtils, 'get_volume_element_name',
                         return_value=tpd.PowerMaxData.volume_id)
      @mock.patch.object(
          common.PowerMaxCommon, 'configure_volume_replication',
          return_value=('first_vol_in_rdf_group', True, True,
                        tpd.PowerMaxData.rep_extra_specs_mgmt, False))
      @mock.patch.object(common.PowerMaxCommon, '_retype_volume')
      @mock.patch.object(rest.PowerMaxRest, 'srdf_resume_replication')
      @mock.patch.object(
          common.PowerMaxCommon, 'break_rdf_device_pair_session',
          return_value=(tpd.PowerMaxData.rep_extra_specs_mgmt, True))
      @mock.patch.object(common.PowerMaxCommon, '_retype_remote_volume')
      @mock.patch.object(utils.PowerMaxUtils, 'is_replication_enabled',
                         return_value=True)
      def test_cleanup_on_migrate_failure(
              self, mck_rep_enabled, mck_retype_remote, mck_break, mck_resume,
              mck_retype, mck_configure, mck_get_vname, mck_protect):
          rdf_pair_broken = True
          rdf_pair_created = True
          vol_retyped = True
          remote_retyped = True
          extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
          target_extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
          rep_extra_specs = deepcopy(self.data.rep_extra_specs_mgmt)
          volume = self.data.test_volume
          volume_name = self.data.volume_id
          device_id = self.data.device_id
          source_sg = self.data.storagegroup_name_f
          array = self.data.array
          srp = extra_specs[utils.SRP]
          slo = extra_specs[utils.SLO]
          workload = extra_specs[utils.WORKLOAD]
          rep_mode = utils.REP_ASYNC
          extra_specs[utils.REP_MODE] = rep_mode
          self.common._cleanup_on_migrate_failure(
              rdf_pair_broken, rdf_pair_created, vol_retyped,
              remote_retyped, extra_specs, target_extra_specs, volume,
              volume_name, device_id, source_sg)
          mck_rep_enabled.assert_called_once_with(extra_specs)
          mck_retype_remote.assert_called_once_with(
              array, volume, device_id, volume_name,
              rep_mode, True, extra_specs)
          mck_break.assert_called_once_with(
              array, device_id, volume_name, extra_specs, volume)
          mck_resume.assert_called_once_with(
              array, rep_extra_specs['mgmt_sg_name'],
              rep_extra_specs['rdf_group_no'], rep_extra_specs)
          mck_retype.assert_called_once_with(
              array, srp, device_id, volume, volume_name,
              target_extra_specs, slo, workload, extra_specs)
          mck_configure.assert_called_once_with(
              array, volume, device_id, extra_specs)
          mck_get_vname.assert_called_once_with(volume.id)
          mck_protect.assert_called_once_with(
              array, source_sg, device_id, volume_name,
              rep_extra_specs, volume)
  
      @mock.patch.object(
          masking.PowerMaxMasking, 'return_volume_to_volume_group')
      @mock.patch.object(
          masking.PowerMaxMasking, 'move_volume_between_storage_groups')
      @mock.patch.object(masking.PowerMaxMasking, 'add_child_sg_to_parent_sg')
      @mock.patch.object(rest.PowerMaxRest, 'create_storage_group')
      @mock.patch.object(rest.PowerMaxRest, 'get_storage_group_list',
                         return_value=['sg'])
      def test_cleanup_on_retype_volume_failure_moved_sg(
              self, mck_get_sgs, mck_create_sg, mck_add_child, mck_move,
              mck_return):
          created_child_sg = False
          add_sg_to_parent = False
          got_default_sg = False
          moved_between_sgs = True
          extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
          array = extra_specs[utils.ARRAY]
          source_sg = self.data.storagegroup_name_f
          parent_sg = self.data.parent_sg_f
          target_sg_name = self.data.storagegroup_name_i
          device_id = self.data.device_id
          volume = self.data.test_volume
          volume_name = self.data.volume_id
          self.common._cleanup_on_retype_volume_failure(
              created_child_sg, add_sg_to_parent, got_default_sg,
              moved_between_sgs, array, source_sg, parent_sg, target_sg_name,
              extra_specs, device_id, volume, volume_name)
          mck_get_sgs.assert_called_once_with(array)
          mck_create_sg.assert_called_once_with(
              array, source_sg, extra_specs['srp'], extra_specs['slo'],
              extra_specs['workload'], extra_specs, False)
          mck_add_child.assert_called_once_with(
              array, source_sg, parent_sg, extra_specs)
          mck_move.assert_called_once_with(
              array, device_id, target_sg_name, source_sg, extra_specs,
              force=True, parent_sg=parent_sg)
          mck_return.assert_called_once_with(
              array, volume, device_id, volume_name, extra_specs)
  
      @mock.patch.object(rest.PowerMaxRest, 'delete_storage_group')
      @mock.patch.object(rest.PowerMaxRest, 'get_volumes_in_storage_group',
                         return_value=[])
      def test_cleanup_on_retype_volume_failure_got_default(
              self, mck_get_vols, mck_del_sg):
          created_child_sg = False
          add_sg_to_parent = False
          got_default_sg = True
          moved_between_sgs = False
          extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
          array = extra_specs[utils.ARRAY]
          source_sg = self.data.storagegroup_name_f
          parent_sg = self.data.parent_sg_f
          target_sg_name = self.data.storagegroup_name_i
          device_id = self.data.device_id
          volume = self.data.test_volume
          volume_name = self.data.volume_id
          self.common._cleanup_on_retype_volume_failure(
              created_child_sg, add_sg_to_parent, got_default_sg,
              moved_between_sgs, array, source_sg, parent_sg, target_sg_name,
              extra_specs, device_id, volume, volume_name)
          mck_get_vols.assert_called_once_with(array, target_sg_name)
          mck_del_sg.assert_called_once_with(array, target_sg_name)
  
      @mock.patch.object(rest.PowerMaxRest, 'delete_storage_group')
      @mock.patch.object(rest.PowerMaxRest, 'remove_child_sg_from_parent_sg')
      def test_cleanup_on_retype_volume_failure_created_child(
              self, mck_remove_child_sg, mck_del_sg):
          created_child_sg = True
          add_sg_to_parent = True
          got_default_sg = False
          moved_between_sgs = False
          extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
          array = extra_specs[utils.ARRAY]
          source_sg = self.data.storagegroup_name_f
          parent_sg = self.data.parent_sg_f
          target_sg_name = self.data.storagegroup_name_i
          device_id = self.data.device_id
          volume = self.data.test_volume
          volume_name = self.data.volume_id
          self.common._cleanup_on_retype_volume_failure(
              created_child_sg, add_sg_to_parent, got_default_sg,
              moved_between_sgs, array, source_sg, parent_sg, target_sg_name,
              extra_specs, device_id, volume, volume_name)
          mck_remove_child_sg.assert_called_once_with(
              array, target_sg_name, parent_sg, extra_specs)
          mck_del_sg.assert_called_once_with(array, target_sg_name)
  
      def test_is_valid_for_storage_assisted_migration_true(self):
          device_id = self.data.device_id
          host = {'host': self.data.new_host}
          volume_name = self.data.test_volume.name
          ref_return = (True, 'Silver', 'OLTP')
          return_val = self.common._is_valid_for_storage_assisted_migration(
              device_id, host, self.data.array,
              self.data.srp, volume_name, False, False)
          self.assertEqual(ref_return, return_val)
          # No current sgs found
          with mock.patch.object(self.rest, 'get_storage_groups_from_volume',
                                 return_value=None):
              return_val = self.common._is_valid_for_storage_assisted_migration(
                  device_id, host, self.data.array, self.data.srp,
                  volume_name, False, False)
              self.assertEqual(ref_return, return_val)
          host = {'host': 'HostX@Backend#Silver+SRP_1+000197800123'}
          ref_return = (True, 'Silver', 'NONE')
          return_val = self.common._is_valid_for_storage_assisted_migration(
              device_id, host, self.data.array,
              self.data.srp, volume_name, False, False)
          self.assertEqual(ref_return, return_val)
  
      def test_is_valid_for_storage_assisted_migration_false(self):
          device_id = self.data.device_id
          volume_name = self.data.test_volume.name
          ref_return = (False, None, None)
          # IndexError
          host = {'host': 'HostX@Backend#Silver+SRP_1+000197800123+dummy+data'}
          return_val = self.common._is_valid_for_storage_assisted_migration(
              device_id, host, self.data.array,
              self.data.srp, volume_name, False, False)
          self.assertEqual(ref_return, return_val)
          # Wrong array
          host2 = {'host': 'HostX@Backend#Silver+OLTP+SRP_1+00012345678'}
          return_val = self.common._is_valid_for_storage_assisted_migration(
              device_id, host2, self.data.array,
              self.data.srp, volume_name, False, False)
          self.assertEqual(ref_return, return_val)
          # Wrong srp
          host3 = {'host': 'HostX@Backend#Silver+OLTP+SRP_2+000197800123'}
          return_val = self.common._is_valid_for_storage_assisted_migration(
              device_id, host3, self.data.array,
              self.data.srp, volume_name, False, False)
          self.assertEqual(ref_return, return_val)
          # Already in correct sg
          host4 = {'host': self.data.fake_host}
          return_val = self.common._is_valid_for_storage_assisted_migration(
              device_id, host4, self.data.array,
              self.data.srp, volume_name, False, False)
          self.assertEqual(ref_return, return_val)
  
      def test_is_valid_for_storage_assisted_migration_next_gen(self):
          device_id = self.data.device_id
          host = {'host': self.data.new_host}
          volume_name = self.data.test_volume.name
          ref_return = (True, 'Silver', 'NONE')
          with mock.patch.object(self.rest, 'is_next_gen_array',
                                 return_value=True):
              return_val = self.common._is_valid_for_storage_assisted_migration(
                  device_id, host, self.data.array,
                  self.data.srp, volume_name, False, False)
              self.assertEqual(ref_return, return_val)
  
      def test_find_volume_group(self):
          group = self.data.test_group_1
          array = self.data.array
          volume_group = self.common._find_volume_group(array, group)
          ref_group = self.data.sg_details_rep[0]
          self.assertEqual(ref_group, volume_group)
  
      def test_get_volume_device_ids(self):
          array = self.data.array
          volumes = [self.data.test_volume]
          ref_device_ids = [self.data.device_id]
          device_ids = self.common._get_volume_device_ids(volumes, array)
          self.assertEqual(ref_device_ids, device_ids)
  
      def test_get_members_of_volume_group(self):
          array = self.data.array
          group_name = self.data.storagegroup_name_source
          ref_volumes = [self.data.device_id, self.data.device_id2]
          member_device_ids = self.common._get_members_of_volume_group(
              array, group_name)
          self.assertEqual(ref_volumes, member_device_ids)
  
      def test_get_members_of_volume_group_empty(self):
          array = self.data.array
          group_name = self.data.storagegroup_name_source
          with mock.patch.object(
                  self.rest, 'get_volumes_in_storage_group',
                  return_value=None):
              member_device_ids = self.common._get_members_of_volume_group(
                  array, group_name
              )
          self.assertIsNone(member_device_ids)
  
      @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                         return_value=True)
      def test_create_group_replica(self, mock_check):
          source_group = self.data.test_group_1
          snap_name = self.data.group_snapshot_name
          with mock.patch.object(
                  self.common,
                  '_create_group_replica') as mock_create_replica:
              self.common._create_group_replica(
                  source_group, snap_name)
              mock_create_replica.assert_called_once_with(
                  source_group, snap_name)
  
      def test_create_group_replica_exception(self):
          source_group = self.data.test_group_failed
          snap_name = self.data.group_snapshot_name
          with mock.patch.object(
                  volume_utils, 'is_group_a_cg_snapshot_type',
                  return_value=True):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common._create_group_replica,
                                source_group,
                                snap_name)
  
      def test_create_group_snapshot(self):
          context = None
          group_snapshot = self.data.test_group_snapshot_1
          snapshots = []
          ref_model_update = {'status': fields.GroupStatus.AVAILABLE}
          with mock.patch.object(
                  volume_utils, 'is_group_a_cg_snapshot_type',
                  return_value=True):
              model_update, snapshots_model_update = (
                  self.common.create_group_snapshot(
                      context, group_snapshot, snapshots))
              self.assertEqual(ref_model_update, model_update)
  
      def test_create_group_snapshot_exception(self):
          context = None
          group_snapshot = self.data.test_group_snapshot_failed
          snapshots = []
          with mock.patch.object(
                  volume_utils, 'is_group_a_cg_snapshot_type',
                  return_value=True):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common.create_group_snapshot,
                                context,
                                group_snapshot,
                                snapshots)
  
      @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                         return_value=True)
      @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
      def test_create_group(self, mock_type, mock_cg_type):
          ref_model_update = {'status': fields.GroupStatus.AVAILABLE}
          model_update = self.common.create_group(None, self.data.test_group_1)
          self.assertEqual(ref_model_update, model_update)
  
      @mock.patch.object(provision.PowerMaxProvision, 'create_volume_group',
                         side_effect=exception.CinderException)
      @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
      def test_create_group_exception(self, mock_type, mock_create):
          context = None
          group = self.data.test_group_failed
          with mock.patch.object(
                  volume_utils, 'is_group_a_cg_snapshot_type',
                  return_value=True):
              self.assertRaises(exception.VolumeBackendAPIException,
                                self.common.create_group,
                                context, group)
  
      def test_delete_group_snapshot(self):
          group_snapshot = self.data.test_group_snapshot_1
          snapshots = []
          context = None
          ref_model_update = {'status': fields.GroupSnapshotStatus.DELETED}
          with mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                                 return_value=True):
              model_update, snapshots_model_update = (
                  self.common.delete_group_snapshot(context,
                                                    group_snapshot, snapshots))
              self.assertEqual(ref_model_update, model_update)
  
      def test_delete_group_snapshot_success(self):
          group_snapshot = self.data.test_group_snapshot_1
          snapshots = []
          ref_model_update = {'status': fields.GroupSnapshotStatus.DELETED}
          with mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                                 return_value=True):
              model_update, snapshots_model_update = (
                  self.common._delete_group_snapshot(group_snapshot,
                                                     snapshots))
              self.assertEqual(ref_model_update, model_update)
  
      def test_delete_group_snapshot_failed(self):
          group_snapshot = self.data.test_group_snapshot_failed
          snapshots = []
          ref_model_update = (
              {'status': fields.GroupSnapshotStatus.ERROR_DELETING})
          with mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                                 return_value=True):
              model_update, snapshots_model_update = (
                  self.common._delete_group_snapshot(group_snapshot,
                                                     snapshots))
              self.assertEqual(ref_model_update, model_update)
  
      @mock.patch.object(volume_utils, 'is_group_a_type',
                         return_value=False)
      @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                         return_value=True)
      def test_update_group(self, mock_cg_type, mock_type_check):
          group = self.data.test_group_1
          add_vols = [self.data.test_volume]
          remove_vols = []
          ref_model_update = {'status': fields.GroupStatus.AVAILABLE}
          model_update, __, __ = self.common.update_group(group,
                                                          add_vols,
                                                          remove_vols)
          self.assertEqual(ref_model_update, model_update)
  
      @mock.patch.object(common.PowerMaxCommon, '_find_volume_group',
                         return_value=None)
      @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                         return_value=True)
      def test_update_group_not_found(self, mock_check, mock_grp):
          self.assertRaises(exception.GroupNotFound, self.common.update_group,
                            self.data.test_group_1, [], [])
  
      @mock.patch.object(common.PowerMaxCommon, '_find_volume_group',
                         side_effect=exception.VolumeBackendAPIException)
      @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                         return_value=True)
      def test_update_group_exception(self, mock_check, mock_grp):
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common.update_group,
                            self.data.test_group_1, [], [])
  
      @mock.patch.object(volume_utils, 'is_group_a_type',
                         return_value=False)
      @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                         return_value=True)
      def test_update_group_remove_volumes(self, mock_cg_type, mock_type_check):
          group = self.data.test_group_1
          add_vols = []
          remove_vols = [self.data.test_volume_group_member]
          ref_model_update = {'status': fields.GroupStatus.AVAILABLE}
          with mock.patch.object(
                  rest.PowerMaxRest, 'is_volume_in_storagegroup',
                  return_value=False) as mock_exists:
              model_update, __, __ = self.common.update_group(group,
                                                              add_vols,
                                                              remove_vols)
              mock_exists.assert_called_once()
  
          self.assertEqual(ref_model_update, model_update)
  
      @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
      def test_delete_group(self, mock_check):
          group = self.data.test_group_1
          volumes = [self.data.test_volume]
          context = None
          ref_model_update = {'status': fields.GroupStatus.DELETED}
          with mock.patch.object(
                  volume_utils, 'is_group_a_cg_snapshot_type',
                  return_value=True), mock.patch.object(
                      self.rest, 'get_volumes_in_storage_group',
                  return_value=[]):
  
              model_update, __ = self.common.delete_group(
                  context, group, volumes)
              self.assertEqual(ref_model_update, model_update)
  
      @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
      def test_delete_group_success(self, mock_check):
          group = self.data.test_group_1
          volumes = []
          ref_model_update = {'status': fields.GroupStatus.DELETED}
          with mock.patch.object(
                  volume_utils, 'is_group_a_cg_snapshot_type',
                  return_value=True), mock.patch.object(
                      self.rest, 'get_volumes_in_storage_group',
                  return_value=[]):
              model_update, __ = self.common._delete_group(group, volumes)
              self.assertEqual(ref_model_update, model_update)
  
      def test_delete_group_already_deleted(self):
          group = self.data.test_group_failed
          ref_model_update = {'status': fields.GroupStatus.DELETED}
          volumes = []
          with mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                                 return_value=True):
              model_update, __ = self.common._delete_group(group, volumes)
              self.assertEqual(ref_model_update, model_update)
  
      @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
      @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                         return_value=True)
      def test_delete_group_failed(self, mock_check, mock_type_check):
          group = self.data.test_group_1
          volumes = []
          ref_model_update = {'status': fields.GroupStatus.ERROR_DELETING}
          with mock.patch.object(
                  self.rest, 'delete_storage_group',
                  side_effect=exception.VolumeBackendAPIException):
              model_update, __ = self.common._delete_group(
                  group, volumes)
          self.assertEqual(ref_model_update, model_update)
  
      @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
      @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
                         return_value=True)
      @mock.patch.object(rest.PowerMaxRest, 'get_volumes_in_storage_group',
                         return_value=[
                             tpd.PowerMaxData.test_volume_group_member])
      @mock.patch.object(common.PowerMaxCommon, '_get_members_of_volume_group',
                         return_value=[tpd.PowerMaxData.device_id])
      @mock.patch.object(common.PowerMaxCommon, '_find_device_on_array',
                         return_value= tpd.PowerMaxData.device_id)
      @mock.patch.object(masking.PowerMaxMasking,
                         'remove_volumes_from_storage_group')
      def test_delete_group_clone_check(
              self, mock_rem, mock_find, mock_mems, mock_vols, mock_chk1,
              mock_chk2):
          group = self.data.test_group_1
          volumes = [self.data.test_volume_group_member]
          with mock.patch.object(
                  self.common, '_clone_check') as mock_clone_chk:
              self.common._delete_group(group, volumes)
              mock_clone_chk.assert_called_once()
  
      @mock.patch.object(
          common.PowerMaxCommon, '_remove_vol_and_cleanup_replication')
      @mock.patch.object(
          masking.PowerMaxMasking, 'remove_volumes_from_storage_group')
      def test_rollback_create_group_from_src(
              self, mock_rm, mock_clean):
          rollback_dict = {
              'target_group_name': self.data.target_group_name,
              'snap_name': 'snap1', 'source_group_name': 'src_grp',
              'volumes': (self.data.device_id, self.data.extra_specs,
                          self.data.test_volume),
              'device_ids': [self.data.device_id],
              'interval_retries_dict': self.data.extra_specs}
          for x in range(0, 2):
              self.common._rollback_create_group_from_src(
                  self.data.array, rollback_dict)
          self.assertEqual(2, mock_rm.call_count)
  
      def test_get_snap_src_dev_list(self):
          src_dev_ids = self.common._get_snap_src_dev_list(
              self.data.array, [self.data.test_snapshot])
          ref_dev_ids = [self.data.device_id]
          self.assertEqual(ref_dev_ids, src_dev_ids)
  
      def test_get_clone_vol_info(self):
          ref_dev_id = self.data.device_id
          source_vols = [self.data.test_volume,
                         self.data.test_attached_volume]
          src_snapshots = [self.data.test_snapshot]
          src_dev_id1, extra_specs1, vol_size1, tgt_vol_name1 = (
              self.common._get_clone_vol_info(
                  self.data.test_clone_volume, source_vols, []))
          src_dev_id2, extra_specs2, vol_size2, tgt_vol_name2 = (
              self.common._get_clone_vol_info(
                  self.data.test_clone_volume, [], src_snapshots))
          self.assertEqual(ref_dev_id, src_dev_id1)
          self.assertEqual(ref_dev_id, src_dev_id2)
  
      def test_get_attributes_from_cinder_config_new_and_old(self):
          kwargs_expected = (
              {'RestServerIp': '1.1.1.1', 'RestServerPort': 8443,
               'RestUserName': 'smc', 'RestPassword': 'smc', 'SSLVerify': False,
               'SerialNumber': self.data.array, 'srpName': 'SRP_1',
               'PortGroup': [self.data.port_group_name_i]})
          old_conf = tpfo.FakeConfiguration(None, 'CommonTests', 1, 1)
          configuration = tpfo.FakeConfiguration(
              None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
              vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
              san_api_port=8443, vmax_port_groups=[self.data.port_group_name_i])
          self.common.configuration = configuration
          kwargs_returned = self.common.get_attributes_from_cinder_config()
          self.assertEqual(kwargs_expected, kwargs_returned)
          self.common.configuration = old_conf
          kwargs = self.common.get_attributes_from_cinder_config()
          self.assertIsNone(kwargs)
  
      def test_get_attributes_from_cinder_config_with_port(self):
          kwargs_expected = (
              {'RestServerIp': '1.1.1.1', 'RestServerPort': 3448,
               'RestUserName': 'smc', 'RestPassword': 'smc', 'SSLVerify': False,
               'SerialNumber': self.data.array, 'srpName': 'SRP_1',
               'PortGroup': [self.data.port_group_name_i]})
          configuration = tpfo.FakeConfiguration(
              None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
              vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
              san_api_port=3448, vmax_port_groups=[self.data.port_group_name_i])
          self.common.configuration = configuration
          kwargs_returned = self.common.get_attributes_from_cinder_config()
          self.assertEqual(kwargs_expected, kwargs_returned)
  
      def test_get_attributes_from_cinder_config_no_port(self):
          kwargs_expected = (
              {'RestServerIp': '1.1.1.1', 'RestServerPort': 8443,
               'RestUserName': 'smc', 'RestPassword': 'smc', 'SSLVerify': False,
               'SerialNumber': self.data.array, 'srpName': 'SRP_1',
               'PortGroup': [self.data.port_group_name_i]})
          configuration = tpfo.FakeConfiguration(
              None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
              vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
              vmax_port_groups=[self.data.port_group_name_i])
          self.common.configuration = configuration
          kwargs_returned = self.common.get_attributes_from_cinder_config()
          self.assertEqual(kwargs_expected, kwargs_returned)
  
      def test_get_ssl_attributes_from_cinder_config(self):
          conf = tpfo.FakeConfiguration(
              None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
              vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
              vmax_port_groups=[self.data.port_group_name_i],
              driver_ssl_cert_verify=True,
              driver_ssl_cert_path='/path/to/cert')
  
          self.common.configuration = conf
          conf_returned = self.common.get_attributes_from_cinder_config()
          self.assertEqual('/path/to/cert', conf_returned['SSLVerify'])
  
          conf.driver_ssl_cert_verify = True
          conf.driver_ssl_cert_path = None
          conf_returned = self.common.get_attributes_from_cinder_config()
          self.assertTrue(conf_returned['SSLVerify'])
  
          conf.driver_ssl_cert_verify = False
          conf.driver_ssl_cert_path = None
          conf_returned = self.common.get_attributes_from_cinder_config()
          self.assertFalse(conf_returned['SSLVerify'])
  
      @mock.patch.object(rest.PowerMaxRest, 'get_size_of_device_on_array',
                         return_value=2.0)
      def test_manage_snapshot_get_size_success(self, mock_get_size):
          size = self.common.manage_existing_snapshot_get_size(
              self.data.test_snapshot)
          self.assertEqual(2, size)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_volume_snap',
                         return_value={'snap_name': 'snap_name'})
      @mock.patch.object(
          common.PowerMaxCommon, 'get_snapshot_metadata',
          return_value={'snap-meta-key-1': 'snap-meta-value-1',
                        'snap-meta-key-2': 'snap-meta-value-2'})
      def test_manage_snapshot_success(self, mck_meta, mock_snap):
          snapshot = deepcopy(self.data.test_snapshot_manage)
          snapshot.metadata = {'user-meta-key-1': 'user-meta-value-1',
                               'user-meta-key-2': 'user-meta-value-2'}
          existing_ref = {u'source-name': u'test_snap'}
          updates_response = self.common.manage_existing_snapshot(
              snapshot, existing_ref)
  
          prov_loc = {'source_id': self.data.device_id,
                      'snap_name': 'OS-%s' % existing_ref['source-name']}
          updates = {'display_name': 'my_snap',
                     'provider_location': six.text_type(prov_loc),
                     'metadata': {'snap-meta-key-1': 'snap-meta-value-1',
                                  'snap-meta-key-2': 'snap-meta-value-2',
                                  'user-meta-key-1': 'user-meta-value-1',
                                  'user-meta-key-2': 'user-meta-value-2'}}
  
          self.assertEqual(updates_response, updates)
  
      def test_manage_snapshot_fail_already_managed(self):
          snapshot = self.data.test_snapshot_manage
          existing_ref = {u'source-name': u'OS-test_snap'}
  
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common.manage_existing_snapshot,
                            snapshot, existing_ref)
  
      @mock.patch.object(utils.PowerMaxUtils, 'is_volume_failed_over',
                         return_value=True)
      def test_manage_snapshot_fail_vol_failed_over(self, mock_failed):
          snapshot = self.data.test_snapshot_manage
          existing_ref = {u'source-name': u'test_snap'}
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common.manage_existing_snapshot,
                            snapshot, existing_ref)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_volume_snap',
                         return_value=False)
      def test_manage_snapshot_fail_vol_not_snap_src(self, mock_snap):
          snapshot = self.data.test_snapshot_manage
          existing_ref = {u'source-name': u'test_snap'}
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common.manage_existing_snapshot,
                            snapshot, existing_ref)
  
      @mock.patch.object(utils.PowerMaxUtils, 'modify_snapshot_prefix',
                         side_effect=exception.VolumeBackendAPIException)
      def test_manage_snapshot_fail_add_prefix(self, mock_mod):
          snapshot = self.data.test_snapshot_manage
          existing_ref = {u'source-name': u'test_snap'}
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common.manage_existing_snapshot,
                            snapshot, existing_ref)
  
      @mock.patch.object(rest.PowerMaxRest, 'modify_volume_snap')
      def test_unmanage_snapshot_success(self, mock_mod, ):
          self.common.unmanage_snapshot(self.data.test_snapshot_manage)
          mock_mod.assert_called_once()
  
      @mock.patch.object(common.PowerMaxCommon, '_sync_check')
      @mock.patch.object(rest.PowerMaxRest, 'modify_volume_snap')
      def test_unmanage_snapshot_no_sync_check(self, mock_mod, mock_sync):
          self.common.unmanage_snapshot(self.data.test_snapshot_manage)
          mock_mod.assert_called_once()
          mock_sync.assert_not_called()
  
      @mock.patch.object(utils.PowerMaxUtils, 'is_volume_failed_over',
                         return_value=True)
      def test_unmanage_snapshot_fail_failover(self, mock_failed):
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common.unmanage_snapshot,
                            self.data.test_snapshot_manage)
  
      @mock.patch.object(rest.PowerMaxRest, 'modify_volume_snap',
                         side_effect=exception.VolumeBackendAPIException)
      def test_unmanage_snapshot_fail_rename(self, mock_snap):
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.common.unmanage_snapshot,
                            self.data.test_snapshot_manage)
  
      @mock.patch.object(provision.PowerMaxProvision, 'delete_volume_snap')
      @mock.patch.object(provision.PowerMaxProvision, 'is_restore_complete',
                         return_value=True)
      @mock.patch.object(common.PowerMaxCommon, '_clone_check')
      @mock.patch.object(provision.PowerMaxProvision, 'revert_volume_snapshot')
      def test_revert_to_snapshot(self, mock_revert, mock_clone,
                                  mock_complete, mock_delete):
          volume = self.data.test_volume
          snapshot = self.data.test_snapshot
          array = self.data.array
          device_id = self.data.device_id
          snap_name = self.data.snap_location['snap_name']
          extra_specs = deepcopy(self.data.extra_specs_intervals_set)
          extra_specs['storagetype:portgroupname'] = (
              self.data.port_group_name_f)
          self.common.revert_to_snapshot(volume, snapshot)
          mock_revert.assert_called_once_with(
              array, device_id, snap_name, extra_specs)
          mock_clone.assert_called_once_with(array, device_id, extra_specs)
          mock_complete.assert_called_once_with(array, device_id,
                                                snap_name, extra_specs)
          mock_delete.assert_called_once_with(array, snap_name, device_id,
                                              restored=True, generation=0)
  
      @mock.patch.object(utils.PowerMaxUtils, 'is_replication_enabled',
                         return_value=True)
      def test_revert_to_snapshot_replicated(self, mock_rep):
          volume = self.data.test_volume
          snapshot = self.data.test_snapshot
          self.assertRaises(exception.VolumeDriverException,
                            self.common.revert_to_snapshot, volume, snapshot)
  
      def test_get_initiator_check_flag(self):
          self.common.configuration.initiator_check = False
          initiator_check = self.common._get_initiator_check_flag()
          self.assertFalse(initiator_check)
  
      def test_get_initiator_check_flag_true(self):
          self.common.configuration.initiator_check = True
          initiator_check = self.common._get_initiator_check_flag()
          self.assertTrue(initiator_check)
  
      def test_get_manageable_volumes_success(self):
          marker = limit = offset = sort_keys = sort_dirs = None
          with mock.patch.object(
                  self.rest, 'get_private_volume_list',
                  return_value=self.data.priv_vol_func_response_single):
              vols_lists = self.common.get_manageable_volumes(
                  marker, limit, offset, sort_keys, sort_dirs)
              expected_response = [
                  {'reference': {'source-id': '00001'}, 'safe_to_manage': True,
                   'size': 1.0, 'reason_not_safe': None, 'cinder_id': None,
                   'extra_info': {'config': 'TDEV', 'emulation': 'FBA'}}]
              self.assertEqual(vols_lists, expected_response)
  
      def test_get_manageable_volumes_filters_set(self):
          marker, limit, offset = '00002', 2, 1
          sort_keys, sort_dirs = 'size', 'desc'
          with mock.patch.object(
                  self.rest, 'get_private_volume_list',
                  return_value=self.data.priv_vol_func_response_multi):
              vols_lists = self.common.get_manageable_volumes(
                  marker, limit, offset, sort_keys, sort_dirs)
              expected_response = [
                  {'reference': {'source-id': '00003'}, 'safe_to_manage': True,
                   'size': 300, 'reason_not_safe': None, 'cinder_id': None,
                   'extra_info': {'config': 'TDEV', 'emulation': 'FBA'}},
                  {'reference': {'source-id': '00004'}, 'safe_to_manage': True,
                   'size': 400, 'reason_not_safe': None, 'cinder_id': None,
                   'extra_info': {'config': 'TDEV', 'emulation': 'FBA'}}]
              self.assertEqual(vols_lists, expected_response)
  
      def test_get_manageable_volumes_fail_no_vols(self):
          marker = limit = offset = sort_keys = sort_dirs = None
          with mock.patch.object(
                  self.rest, 'get_private_volume_list',
                  return_value=[]):
              expected_response = []
              vol_list = self.common.get_manageable_volumes(
                  marker, limit, offset, sort_keys, sort_dirs)
              self.assertEqual(vol_list, expected_response)
  
      def test_get_manageable_volumes_fail_no_valid_vols(self):
          marker = limit = offset = sort_keys = sort_dirs = None
          with mock.patch.object(
                  self.rest, 'get_private_volume_list',
                  return_value=self.data.priv_vol_func_response_multi_invalid):
              expected_response = []
              vol_list = self.common.get_manageable_volumes(
                  marker, limit, offset, sort_keys, sort_dirs)
              self.assertEqual(vol_list, expected_response)
  
      def test_get_manageable_snapshots_success(self):
          marker = limit = offset = sort_keys = sort_dirs = None
          with mock.patch.object(
                  self.rest, 'get_private_volume_list',
                  return_value=self.data.priv_vol_func_response_single):
              snap_list = self.common.get_manageable_snapshots(
                  marker, limit, offset, sort_keys, sort_dirs)
              expected_response = [{
                  'reference': {'source-name': 'testSnap1'},
                  'safe_to_manage': True, 'size': 1,
                  'reason_not_safe': None, 'cinder_id': None,
                  'extra_info': {
                      'generation': 0, 'secured': False, 'timeToLive': 'N/A',
                      'timestamp': mock.ANY},
                  'source_reference': {'source-id': '00001'}}]
              self.assertEqual(snap_list, expected_response)
  
      def test_get_manageable_snapshots_filters_set(self):
          marker, limit, offset = 'testSnap2', 2, 1
          sort_keys, sort_dirs = 'size', 'desc'
          with mock.patch.object(
                  self.rest, 'get_private_volume_list',
                  return_value=self.data.priv_vol_func_response_multi):
              vols_lists = self.common.get_manageable_snapshots(
                  marker, limit, offset, sort_keys, sort_dirs)
              expected_response = [
                  {'reference': {'source-name': 'testSnap3'},
                   'safe_to_manage': True, 'size': 300, 'reason_not_safe': None,
                   'cinder_id': None, 'extra_info': {
                      'generation': 0, 'secured': False, 'timeToLive': 'N/A',
                      'timestamp': mock.ANY},
                   'source_reference': {'source-id': '00003'}},
                  {'reference': {'source-name': 'testSnap4'},
                   'safe_to_manage': True, 'size': 400, 'reason_not_safe': None,
                   'cinder_id': None, 'extra_info': {
                      'generation': 0, 'secured': False, 'timeToLive': 'N/A',
                      'timestamp': mock.ANY},
                   'source_reference': {'source-id': '00004'}}]
              self.assertEqual(vols_lists, expected_response)
  
      def test_get_manageable_snapshots_fail_no_snaps(self):
          marker = limit = offset = sort_keys = sort_dirs = None
          with mock.patch.object(self.rest, 'get_private_volume_list',
                                 return_value=[]):
              expected_response = []
              vols_lists = self.common.get_manageable_snapshots(
                  marker, limit, offset, sort_keys, sort_dirs)
              self.assertEqual(vols_lists, expected_response)
  
      def test_get_manageable_snapshots_fail_no_valid_snaps(self):
          marker = limit = offset = sort_keys = sort_dirs = None
          with mock.patch.object(
                  self.rest, 'get_private_volume_list',
                  return_value=self.data.priv_vol_func_response_multi_invalid):
              expected_response = []
              vols_lists = self.common.get_manageable_snapshots(
                  marker, limit, offset, sort_keys, sort_dirs)
              self.assertEqual(vols_lists, expected_response)
  
      def test_get_slo_workload_combo_from_cinder_conf(self):
          self.common.configuration.vmax_service_level = 'Diamond'
          self.common.configuration.vmax_workload = 'DSS'
          response1 = self.common.get_attributes_from_cinder_config()
          self.assertEqual('Diamond', response1['ServiceLevel'])
          self.assertEqual('DSS', response1['Workload'])
  
          self.common.configuration.vmax_service_level = 'Diamond'
          self.common.configuration.vmax_workload = None
          response2 = self.common.get_attributes_from_cinder_config()
          self.assertEqual(self.common.configuration.vmax_service_level,
                           response2['ServiceLevel'])
          self.assertIsNone(response2['Workload'])
  
          expected_response = {
              'RestServerIp': '1.1.1.1', 'RestServerPort': 8443,
              'RestUserName': 'smc', 'RestPassword': 'smc', 'SSLVerify': False,
              'SerialNumber': '000197800123', 'srpName': 'SRP_1',
              'PortGroup': ['OS-fibre-PG']}
  
          self.common.configuration.vmax_service_level = None
          self.common.configuration.vmax_workload = 'DSS'
          response3 = self.common.get_attributes_from_cinder_config()
          self.assertEqual(expected_response, response3)
  
          self.common.configuration.vmax_service_level = None
          self.common.configuration.vmax_workload = None
          response4 = self.common.get_attributes_from_cinder_config()
          self.assertEqual(expected_response, response4)
  
      def test_get_u4p_failover_info(self):
          configuration = tpfo.FakeConfiguration(
              None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='test',
              san_password='test', san_api_port=8443,
              driver_ssl_cert_verify='/path/to/cert',
              u4p_failover_target=(self.data.u4p_failover_config[
                  'u4p_failover_targets']), u4p_failover_backoff_factor='2',
              u4p_failover_retries='3', u4p_failover_timeout='10',
              u4p_primary='10.10.10.10')
          self.common.configuration = configuration
          self.common._get_u4p_failover_info()
          self.assertTrue(self.rest.u4p_failover_enabled)
          self.assertIsNotNone(self.rest.u4p_failover_targets)
  
      def test_update_vol_stats_retest_u4p(self):
          self.rest.u4p_in_failover = True
          self.rest.u4p_failover_autofailback = True
          with mock.patch.object(
                  self.common, 'retest_primary_u4p') as mock_retest:
              self.common.update_volume_stats()
              mock_retest.assert_called_once()
  
          self.rest.u4p_in_failover = True
          self.rest.u4p_failover_autofailback = False
          with mock.patch.object(
                  self.common, 'retest_primary_u4p') as mock_retest:
              self.common.update_volume_stats()
              mock_retest.assert_not_called()
  
      @mock.patch.object(rest.PowerMaxRest, 'request', return_value=[200, None])
      @mock.patch.object(
          common.PowerMaxCommon, 'get_attributes_from_cinder_config',
          return_value=tpd.PowerMaxData.u4p_failover_target[0])
      def test_retest_primary_u4p(self, mock_primary_u4p, mock_request):
          self.common.retest_primary_u4p()
          self.assertFalse(self.rest.u4p_in_failover)
  
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(None, False, None))
      @mock.patch.object(common.PowerMaxCommon, '_sync_check')
      def test_extend_vol_validation_checks_success(self, mck_sync, mck_rep):
          volume = self.data.test_volume
          array = self.data.array
          device_id = self.data.device_id
          new_size = self.data.test_volume.size + 1
          extra_specs = self.data.extra_specs
          self.common._extend_vol_validation_checks(
              array, device_id, volume.name, extra_specs, volume.size, new_size)
  
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(None, False, None))
      @mock.patch.object(common.PowerMaxCommon, '_sync_check')
      def test_extend_vol_val_check_no_device(self, mck_sync, mck_rep):
          volume = self.data.test_volume
          array = self.data.array
          device_id = None
          new_size = self.data.test_volume.size + 1
          extra_specs = self.data.extra_specs
          self.assertRaises(
              exception.VolumeBackendAPIException,
              self.common._extend_vol_validation_checks,
              array, device_id, volume.name, extra_specs, volume.size, new_size)
  
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(None, True, None))
      @mock.patch.object(common.PowerMaxCommon, '_sync_check')
      def test_extend_vol_val_check_snap_src(self, mck_sync, mck_rep):
          volume = self.data.test_volume
          array = self.data.array
          device_id = self.data.device_id
          new_size = self.data.test_volume.size + 1
          extra_specs = deepcopy(self.data.extra_specs)
          self.common.next_gen = False
          self.assertRaises(
              exception.VolumeBackendAPIException,
              self.common._extend_vol_validation_checks,
              array, device_id, volume.name, extra_specs, volume.size, new_size)
  
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(None, False, None))
      @mock.patch.object(common.PowerMaxCommon, '_sync_check')
      def test_extend_vol_val_check_wrong_size(self, mck_sync, mck_rep):
          volume = self.data.test_volume
          array = self.data.array
          device_id = self.data.device_id
          new_size = volume.size - 1
          extra_specs = self.data.extra_specs
          self.assertRaises(
              exception.VolumeBackendAPIException,
              self.common._extend_vol_validation_checks,
              array, device_id, volume.name, extra_specs, volume.size, new_size)
  
      def test_array_ode_capabilities_check_non_next_gen_local(self):
          """Rep enabled, neither array next gen, returns F,F,F,F"""
          array = self.data.powermax_model_details['symmetrixId']
          self.common.next_gen = False
          (r1_ode, r1_ode_metro,
           r2_ode, r2_ode_metro) = self.common._array_ode_capabilities_check(
              array, self.data.rep_config_metro, True)
          self.assertFalse(r1_ode)
          self.assertFalse(r1_ode_metro)
          self.assertFalse(r2_ode)
          self.assertFalse(r2_ode_metro)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_array_detail',
                         return_value={'ucode': '5977.1.1'})
      @mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
                         return_value=(10, tpd.PowerMaxData.remote_array))
      def test_array_ode_capabilities_check_next_gen_non_rep_pre_elm(
              self, mock_rdf, mock_det):
          """Rep disabled, local array next gen, pre elm, returns T,F,F,F"""
          array = self.data.powermax_model_details['symmetrixId']
          self.common.ucode_level = '5978.1.1'
          self.common.next_gen = True
          (r1_ode, r1_ode_metro,
           r2_ode, r2_ode_metro) = self.common._array_ode_capabilities_check(
              array, self.data.rep_config_metro, False)
          self.assertTrue(r1_ode)
          self.assertFalse(r1_ode_metro)
          self.assertFalse(r2_ode)
          self.assertFalse(r2_ode_metro)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_array_detail',
                         return_value={'ucode': '5977.1.1'})
      @mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
                         return_value=(10, tpd.PowerMaxData.remote_array))
      def test_array_ode_capabilities_check_next_gen_remote_rep(
              self, mock_rdf, mock_det):
          """Rep enabled, remote not next gen, returns T,T,F,F"""
          array = self.data.powermax_model_details['symmetrixId']
          self.common.ucode_level = self.data.powermax_model_details['ucode']
          self.common.next_gen = True
          (r1_ode, r1_ode_metro,
           r2_ode, r2_ode_metro) = self.common._array_ode_capabilities_check(
              array, self.data.rep_config_metro, True)
          self.assertTrue(r1_ode)
          self.assertTrue(r1_ode_metro)
          self.assertFalse(r2_ode)
          self.assertFalse(r2_ode_metro)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_array_detail',
                         return_value={'ucode': '5978.1.1'})
      @mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
                         return_value=(10, tpd.PowerMaxData.remote_array))
      def test_array_ode_capabilities_check_next_gen_pre_elm_rep(
              self, mock_rdf, mock_det):
          """Rep enabled, both array next gen, tgt<5978.221, returns T,T,T,F"""
          array = self.data.powermax_model_details['symmetrixId']
          self.common.ucode_level = self.data.powermax_model_details['ucode']
          self.common.next_gen = True
          (r1_ode, r1_ode_metro,
           r2_ode, r2_ode_metro) = self.common._array_ode_capabilities_check(
              array, self.data.rep_config_metro, True)
          self.assertTrue(r1_ode)
          self.assertTrue(r1_ode_metro)
          self.assertTrue(r2_ode)
          self.assertFalse(r2_ode_metro)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_array_detail',
                         return_value=tpd.PowerMaxData.ucode_5978_foxtail)
      @mock.patch.object(common.PowerMaxCommon, 'get_rdf_details',
                         return_value=(10, tpd.PowerMaxData.remote_array))
      def test_array_ode_capabilities_check_next_gen_post_elm_rep(
              self, mock_rdf, mock_det):
          """Rep enabled, both array next gen, tgt>5978.221 returns T,T,T,T"""
          array = self.data.powermax_model_details['symmetrixId']
          self.common.ucode_level = self.data.powermax_model_details['ucode']
          self.common.next_gen = True
          (r1_ode, r1_ode_metro,
           r2_ode, r2_ode_metro) = self.common._array_ode_capabilities_check(
              array, self.data.rep_config_metro, True)
          self.assertTrue(r1_ode)
          self.assertTrue(r1_ode_metro)
          self.assertTrue(r2_ode)
          self.assertTrue(r2_ode_metro)
  
      @mock.patch.object(rest.PowerMaxRest, 'srdf_resume_replication')
      @mock.patch.object(common.PowerMaxCommon, '_protect_storage_group')
      @mock.patch.object(
          common.PowerMaxCommon, 'configure_volume_replication',
          return_value=('first_vol_in_rdf_group', None, None,
                        tpd.PowerMaxData.rep_extra_specs_mgmt, True))
      @mock.patch.object(provision.PowerMaxProvision, 'extend_volume')
      @mock.patch.object(common.PowerMaxCommon, 'break_rdf_device_pair_session')
      def test_extend_legacy_replicated_vol(
              self, mck_break, mck_extend, mck_configure, mck_protect, mck_res):
          volume = self.data.test_volume_group_member
          array = self.data.array
          device_id = self.data.device_id
          new_size = volume.size + 1
          extra_specs = self.data.extra_specs
          rdf_group_no = self.data.rdf_group_no_1
          self.common._extend_legacy_replicated_vol(
              array, volume, device_id, volume.name, new_size, extra_specs,
              rdf_group_no)
          mck_protect.assert_called_once()
          mck_res.assert_called_once()
  
      @mock.patch.object(
          common.PowerMaxCommon, 'break_rdf_device_pair_session',
          side_effect=exception.VolumeBackendAPIException)
      def test_extend_legacy_replicated_vol_fail(self, mck_resume):
          volume = self.data.test_volume_group_member
          array = self.data.array
          device_id = self.data.device_id
          new_size = volume.size + 1
          extra_specs = self.data.extra_specs
          rdf_group_no = self.data.rdf_group_no_1
          self.assertRaises(
              exception.VolumeBackendAPIException,
              self.common._extend_legacy_replicated_vol,
              array, device_id, volume.name, extra_specs, volume.size, new_size,
              rdf_group_no)
  
      def test_get_unisphere_port(self):
          # Test user set port ID
          configuration = tpfo.FakeConfiguration(
              None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
              vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
              san_api_port=1234, vmax_port_groups=[self.data.port_group_name_i])
          self.common.configuration = configuration
          port = self.common._get_unisphere_port()
          self.assertEqual(1234, port)
  
          # Test no set port ID, use default port
          configuration = tpfo.FakeConfiguration(
              None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
              vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
              vmax_port_groups=[self.data.port_group_name_i])
          self.common.configuration = configuration
          ref_port = utils.DEFAULT_PORT
          port = self.common._get_unisphere_port()
          self.assertEqual(ref_port, port)
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_do_sync_check')
      def test_sync_check_no_source_device_on_array(self, mock_check):
          with mock.patch.object(self.rest, 'get_volume',
                                 side_effect=exception.VolumeBackendAPIException(
                                     "404 00123 does not exist")):
              array = self.data.array
              device_id = self.data.device_id
              extra_specs = self.data.extra_specs
              self.common._sync_check(array, device_id, extra_specs,
                                      source_device_id='00123')
              mock_check.assert_not_called()
  
      def test_sync_check(self):
          array = self.data.array
          device_id = self.data.device_id
          extra_specs = self.data.extra_specs
  
          with mock.patch.object(self.common, '_do_sync_check') as mck_sync:
              self.common._sync_check(array, device_id, extra_specs, False,
                                      self.data.device_id2)
              mck_sync.assert_called_with(array, self.data.device_id2,
                                          extra_specs, False)
              mck_sync.reset_mock()
              with mock.patch.object(self.common, '_get_target_source_device',
                                     return_value=self.data.device_id3):
                  self.common._sync_check(array, device_id, extra_specs, True)
                  mck_sync.assert_called_with(array, self.data.device_id3,
                                              extra_specs, True)
              mck_sync.reset_mock()
              self.common._sync_check(array, device_id, extra_specs)
              mck_sync.assert_called_with(array, device_id, extra_specs, False)
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_unlink_targets_and_delete_temp_snapvx')
      @mock.patch.object(rest.PowerMaxRest, 'find_snap_vx_sessions',
                         return_value=(tpd.PowerMaxData.snap_src_sessions,
                                       tpd.PowerMaxData.snap_tgt_session))
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(True, True, False))
      def test_do_sync_check(self, mck_rep, mck_find, mck_unlink):
  
          array = self.data.array
          device_id = self.data.device_id
          extra_specs = self.data.extra_specs
          self.common._do_sync_check(array, device_id, extra_specs)
          self.assertEqual(3, mck_unlink.call_count)
  
      @mock.patch.object(provision.PowerMaxProvision, 'delete_temp_volume_snap')
      @mock.patch.object(provision.PowerMaxProvision, 'unlink_snapvx_tgt_volume')
      def test_unlink_targets_and_delete_temp_snapvx(self, mck_break, mck_del):
          array = self.data.array
          extra_specs = self.data.extra_specs
          session = self.data.snap_tgt_session_cm_enabled
          snap_name = session['snap_name']
          source = session['source_vol_id']
          generation = session['generation']
          target = session['target_vol_id']
  
          self.common._unlink_targets_and_delete_temp_snapvx(
              session, array, extra_specs)
          mck_break.assert_called_with(array, target, source, snap_name,
                                       extra_specs, generation, True)
          mck_del.assert_called_once_with(array, snap_name, source, generation)
  
          mck_break.reset_mock()
          mck_del.reset_mock()
  
          session['copy_mode'] = False
          session['expired'] = True
          self.common._unlink_targets_and_delete_temp_snapvx(
              session, array, extra_specs)
          mck_break.assert_called_with(array, target, source, snap_name,
                                       extra_specs, generation, False)
          mck_del.assert_not_called()
  
      @mock.patch.object(rest.PowerMaxRest, 'find_snap_vx_sessions',
                         return_value=(None, tpd.PowerMaxData.snap_tgt_session))
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(True, False, False))
      def test_get_target_source_device(self, mck_rep, mck_find):
          array = self.data.array
          tgt_device = self.data.device_id2
          src_device = self.common._get_target_source_device(array, tgt_device)
          self.assertEqual(src_device, self.data.device_id)
  
      @mock.patch.object(common.PowerMaxCommon, '_delete_valid_snapshot')
      @mock.patch.object(rest.PowerMaxRest, 'find_snap_vx_sessions',
                         return_value=(tpd.PowerMaxData.snap_src_sessions,
                                       tpd.PowerMaxData.snap_tgt_session))
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(True, True, False))
      def test_clone_check(self, mck_rep, mck_find, mck_del):
          array = self.data.array
          device_id = self.data.device_id
          extra_specs = self.data.extra_specs
          self.common.snapvx_unlink_limit = 3
          self.common._clone_check(array, device_id, extra_specs)
          self.assertEqual(3, mck_del.call_count)
  
      @mock.patch.object(
          common.PowerMaxCommon, '_unlink_targets_and_delete_temp_snapvx')
      @mock.patch.object(rest.PowerMaxRest, 'find_snap_vx_sessions',
                         return_value=(tpd.PowerMaxData.snap_src_sessions,
                                       tpd.PowerMaxData.snap_tgt_session))
      @mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
                         return_value=(True, True, False))
      def test_clone_check_force_unlink(self, mck_rep, mck_find, mck_del):
          array = self.data.array
          device_id = self.data.device_id
          extra_specs = self.data.extra_specs
          self.common.snapvx_unlink_limit = 3
          self.common._clone_check(
              array, device_id, extra_specs, force_unlink=True)
          self.assertEqual(3, mck_del.call_count)
  
      @mock.patch.object(common.PowerMaxCommon,
                         '_unlink_targets_and_delete_temp_snapvx')
      def test_delete_valid_snapshot(self, mck_unlink):
  
          array = self.data.array
          extra_specs = self.data.extra_specs
  
          session = {'snap_name': 'EMC_SMI_TEST', 'expired': False}
          self.common._delete_valid_snapshot(array, session, extra_specs)
          mck_unlink.assert_called_with(session, array, extra_specs)
          mck_unlink.reset_mock()
  
          session = {'snap_name': 'temp-000AA-snapshot_for_clone',
                     'expired': True}
          self.common._delete_valid_snapshot(array, session, extra_specs)
          mck_unlink.assert_called_with(session, array, extra_specs)
          mck_unlink.reset_mock()
  
          session = {'snap_name': 'temp-000AA-snapshot_for_clone',
                     'expired': False}
          self.common._delete_valid_snapshot(array, session, extra_specs)
          mck_unlink.assert_not_called()
  
      def test_delete_valid_snapshot_exception(self):
  
          array = self.data.array
          extra_specs = self.data.extra_specs
          session = {'snap_name': 'temp-000AA-snapshot_for_clone',
                     'expired': True}
  
          with mock.patch.object(
                  self.common, '_unlink_targets_and_delete_temp_snapvx',
                  side_effect=exception.VolumeBackendAPIException(
                      "404 temp-000AA-snapshot_for_clone does not exist")
          ) as mck_unlink:
              self.common._delete_valid_snapshot(array, session, extra_specs)
              mck_unlink.assert_called_with(session, array, extra_specs)
  
          with mock.patch.object(
                  self.common, '_unlink_targets_and_delete_temp_snapvx',
                  side_effect=exception.VolumeBackendAPIException(
                      "500 internal server error")):
              self.assertRaises(
                  exception.VolumeBackendAPIException,
                  self.common._unlink_targets_and_delete_temp_snapvx,
                  array, session, extra_specs)
  
      @mock.patch.object(rest.PowerMaxRest, '_get_private_volume',
                         return_value=tpd.PowerMaxData.priv_vol_response_rep)
      @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
                         return_value=(tpd.PowerMaxData.array_model, None))
      @mock.patch.object(rest.PowerMaxRest, 'get_rdf_group',
                         return_value=(tpd.PowerMaxData.rdf_group_details))
      def test_get_volume_metadata_rep(self, mck_rdf, mck_model, mck_priv):
          ref_metadata = {
              'DeviceID': self.data.device_id,
              'DeviceLabel': self.data.device_label, 'ArrayID': self.data.array,
              'ArrayModel': self.data.array_model, 'ServiceLevel': 'None',
              'Workload': 'None', 'Emulation': 'FBA', 'Configuration': 'TDEV',
              'CompressionDisabled': 'True', 'ReplicationEnabled': 'True',
              'R2-DeviceID': self.data.device_id2,
              'R2-ArrayID': self.data.remote_array,
              'R2-ArrayModel': self.data.array_model,
              'ReplicationMode': 'Synchronized',
              'RDFG-Label': self.data.rdf_group_name_1,
              'R1-RDFG': 1, 'R2-RDFG': 1}
          array = self.data.array
          device_id = self.data.device_id
          act_metadata = self.common.get_volume_metadata(array, device_id)
          self.assertEqual(ref_metadata, act_metadata)
  
      @mock.patch.object(rest.PowerMaxRest, '_get_private_volume',
                         return_value=tpd.PowerMaxData.
                         priv_vol_response_metro_active_rep)
      @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
                         return_value=(tpd.PowerMaxData.array_model, None))
      @mock.patch.object(rest.PowerMaxRest, 'get_rdf_group',
                         return_value=(tpd.PowerMaxData.rdf_group_details))
      def test_get_volume_metadata_metro_active_rep(self, mck_rdf,
                                                    mck_model, mck_priv):
          ref_metadata = {
              'DeviceID': self.data.device_id,
              'DeviceLabel': self.data.device_label, 'ArrayID': self.data.array,
              'ArrayModel': self.data.array_model, 'ServiceLevel': 'None',
              'Workload': 'None', 'Emulation': 'FBA', 'Configuration': 'TDEV',
              'CompressionDisabled': 'True', 'ReplicationEnabled': 'True',
              'R2-DeviceID': self.data.device_id2,
              'R2-ArrayID': self.data.remote_array,
              'R2-ArrayModel': self.data.array_model,
              'ReplicationMode': 'Metro',
              'RDFG-Label': self.data.rdf_group_name_1,
              'R1-RDFG': 1, 'R2-RDFG': 1}
          array = self.data.array
          device_id = self.data.device_id
          act_metadata = self.common.get_volume_metadata(array, device_id)
          self.assertEqual(ref_metadata, act_metadata)
  
      @mock.patch.object(rest.PowerMaxRest, '_get_private_volume',
                         return_value=tpd.PowerMaxData.priv_vol_response_no_rep)
      @mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
                         return_value=(tpd.PowerMaxData.array_model, None))
      def test_get_volume_metadata_no_rep(self, mck_model, mck_priv):
          ref_metadata = {
              'DeviceID': self.data.device_id,
              'DeviceLabel': self.data.device_label, 'ArrayID': self.data.array,
              'ArrayModel': self.data.array_model, 'ServiceLevel': 'None',
              'Workload': 'None', 'Emulation': 'FBA', 'Configuration': 'TDEV',
              'CompressionDisabled': 'True', 'ReplicationEnabled': 'False'}
          array = self.data.array
          device_id = self.data.device_id
          act_metadata = self.common.get_volume_metadata(array, device_id)
          self.assertEqual(ref_metadata, act_metadata)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_volume_snap_info',
                         return_value=tpd.PowerMaxData.priv_snap_response)
      def test_get_snapshot_metadata(self, mck_snap):
          array = self.data.array
          device_id = self.data.device_id
          device_label = self.data.managed_snap_id
          snap_name = self.data.test_snapshot_snap_name
          ref_metadata = {'SnapshotLabel': snap_name,
                          'SourceDeviceID': device_id,
                          'SourceDeviceLabel': device_label}
  
          act_metadata = self.common.get_snapshot_metadata(
              array, device_id, snap_name)
          self.assertEqual(ref_metadata, act_metadata)
  
      def test_update_metadata(self):
          model_update = {'provider_location': six.text_type(
              self.data.provider_location)}
          ref_model_update = (
              {'provider_location': six.text_type(self.data.provider_location),
               'metadata': {'device-meta-key-1': 'device-meta-value-1',
                            'device-meta-key-2': 'device-meta-value-2',
                            'user-meta-key-1': 'user-meta-value-1',
                            'user-meta-key-2': 'user-meta-value-2'}})
  
          existing_metadata = {'user-meta-key-1': 'user-meta-value-1',
                               'user-meta-key-2': 'user-meta-value-2'}
  
          object_metadata = {'device-meta-key-1': 'device-meta-value-1',
                             'device-meta-key-2': 'device-meta-value-2'}
  
          model_update = self.common.update_metadata(
              model_update, existing_metadata, object_metadata)
          self.assertEqual(ref_model_update, model_update)
  
      def test_update_metadata_no_model(self):
          model_update = None
          ref_model_update = (
              {'metadata': {'device-meta-key-1': 'device-meta-value-1',
                            'device-meta-key-2': 'device-meta-value-2',
                            'user-meta-key-1': 'user-meta-value-1',
                            'user-meta-key-2': 'user-meta-value-2'}})
  
          existing_metadata = {'user-meta-key-1': 'user-meta-value-1',
                               'user-meta-key-2': 'user-meta-value-2'}
  
          object_metadata = {'device-meta-key-1': 'device-meta-value-1',
                             'device-meta-key-2': 'device-meta-value-2'}
  
          model_update = self.common.update_metadata(
              model_update, existing_metadata, object_metadata)
          self.assertEqual(ref_model_update, model_update)
  
      def test_update_metadata_no_existing_metadata(self):
          model_update = {'provider_location': six.text_type(
              self.data.provider_location)}
          ref_model_update = (
              {'provider_location': six.text_type(self.data.provider_location),
               'metadata': {'device-meta-key-1': 'device-meta-value-1',
                            'device-meta-key-2': 'device-meta-value-2'}})
  
          existing_metadata = None
  
          object_metadata = {'device-meta-key-1': 'device-meta-value-1',
                             'device-meta-key-2': 'device-meta-value-2'}
  
          model_update = self.common.update_metadata(
              model_update, existing_metadata, object_metadata)
          self.assertEqual(ref_model_update, model_update)
  
      def test_update_metadata_model_list_exception(self):
          model_update = [{'provider_location': six.text_type(
              self.data.provider_location)}]
  
          existing_metadata = None
  
          object_metadata = {'device-meta-key-1': 'device-meta-value-1',
                             'device-meta-key-2': 'device-meta-value-2'}
  
          self.assertRaises(
              exception.VolumeBackendAPIException,
              self.common.update_metadata, model_update, existing_metadata,
              object_metadata)
  
      def test_remove_stale_data(self):
          ret_model_update = self.common.remove_stale_data(
              self.data.replication_model)
          self.assertEqual(self.data.non_replication_model, ret_model_update)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_storage_group',
                         return_value=tpd.PowerMaxData.add_volume_sg_info_dict)
      def test_get_tags_of_storage_group_none(self, mock_sg):
          self.assertIsNone(self.common.get_tags_of_storage_group(
              self.data.array, self.data.defaultstoragegroup_name))
  
      @mock.patch.object(rest.PowerMaxRest, 'get_storage_group',
                         return_value=tpd.PowerMaxData.storage_group_with_tags)
      def test_get_tags_of_storage_group_exists(self, mock_sg):
          tag_list = self.common.get_tags_of_storage_group(
              self.data.array, self.data.defaultstoragegroup_name)
          self.assertEqual(tpd.PowerMaxData.sg_tags, tag_list)
  
      @mock.patch.object(rest.PowerMaxRest, 'get_storage_group',
                         side_effect=exception.APIException)
      def test_get_tags_of_storage_group_exception(self, mock_sg):
          self.assertIsNone(self.common.get_tags_of_storage_group(
              self.data.array, self.data.storagegroup_name_f))
  
      @mock.patch.object(rest.PowerMaxRest, 'add_storage_array_tags')
      @mock.patch.object(rest.PowerMaxRest, 'get_array_tags',
                         return_value=[])
      def test_check_and_add_tags_to_storage_array(
              self, mock_get_tags, mock_add_tags):
          array_tag_list = ['OpenStack']
          self.common._check_and_add_tags_to_storage_array(
              self.data.array, array_tag_list, self.data.extra_specs)
          mock_add_tags.assert_called_with(
              self.data.array, array_tag_list, self.data.extra_specs)
  
      @mock.patch.object(rest.PowerMaxRest, 'add_storage_array_tags')
      @mock.patch.object(rest.PowerMaxRest, 'get_array_tags',
                         return_value=[])
      def test_check_and_add_tags_to_storage_array_add_2_tags(
              self, mock_get_tags, mock_add_tags):
          array_tag_list = ['OpenStack', 'Production']
          self.common._check_and_add_tags_to_storage_array(
              self.data.array, array_tag_list, self.data.extra_specs)
          mock_add_tags.assert_called_with(
              self.data.array, array_tag_list, self.data.extra_specs)
  
      @mock.patch.object(rest.PowerMaxRest, 'add_storage_array_tags')
      @mock.patch.object(rest.PowerMaxRest, 'get_array_tags',
                         return_value=['Production'])
      def test_check_and_add_tags_to_storage_array_add_1_tags(
              self, mock_get_tags, mock_add_tags):
          array_tag_list = ['OpenStack', 'Production']
          add_tag_list = ['OpenStack']
          self.common._check_and_add_tags_to_storage_array(
              self.data.array, array_tag_list, self.data.extra_specs)
          mock_add_tags.assert_called_with(
              self.data.array, add_tag_list, self.data.extra_specs)
  
      @mock.patch.object(rest.PowerMaxRest, 'add_storage_array_tags')
      @mock.patch.object(rest.PowerMaxRest, 'get_array_tags',
                         return_value=['openstack'])
      def test_check_and_add_tags_to_storage_array_already_tagged(
              self, mock_get_tags, mock_add_tags):
          array_tag_list = ['OpenStack']
          self.common._check_and_add_tags_to_storage_array(
              self.data.array, array_tag_list, self.data.extra_specs)
          mock_add_tags.assert_not_called()
  
      @mock.patch.object(rest.PowerMaxRest, 'get_array_tags',
                         return_value=[])
      def test_check_and_add_tags_to_storage_array_invalid_tag(
              self, mock_get_tags):
          array_tag_list = ['Open$tack']
          self.assertRaises(
              exception.VolumeBackendAPIException,
              self.common._check_and_add_tags_to_storage_array,
              self.data.array, array_tag_list, self.data.extra_specs)
  
      def test_validate_storage_group_tag_list_good_tag_list(self):
          self.common._validate_storage_group_tag_list(
              self.data.vol_type_extra_specs_tags)
  
      @mock.patch.object(utils.PowerMaxUtils, 'verify_tag_list')
      def test_validate_storage_group_tag_list_no_tag_list(
              self, mock_verify):
          self.common._validate_storage_group_tag_list(
              self.data.extra_specs)
          mock_verify.assert_not_called()
  
      def test_set_config_file_and_get_extra_specs(self):
          self.common.rep_config = {
              'mode': utils.REP_METRO, utils.METROBIAS: True}
          with mock.patch.object(self.utils, 'get_volumetype_extra_specs',
                                 return_value=self.data.rep_extra_specs_metro):
              extra_specs, __ = self.common._set_config_file_and_get_extra_specs(
                  self.data.test_volume, None)
              self.assertEqual(self.data.rep_extra_specs_metro, extra_specs)
  
      @mock.patch.object(rest.PowerMaxRest, 'is_volume_in_storagegroup',
                         return_value=True)
      @mock.patch.object(masking.PowerMaxMasking,
                         'return_volume_to_volume_group')
      @mock.patch.object(masking.PowerMaxMasking,
                         'move_volume_between_storage_groups')
      @mock.patch.object(
          masking.PowerMaxMasking, 'get_or_create_default_storage_group',
          return_value=tpd.PowerMaxData.rdf_managed_async_grp)
      @mock.patch.object(rest.PowerMaxRest, 'get_volume',
                         return_value=tpd.PowerMaxData.volume_details[0])
      @mock.patch.object(utils.PowerMaxUtils, 'get_rdf_management_group_name',
                         return_value=tpd.PowerMaxData.rdf_managed_async_grp)
      def test_retype_volume_detached(
              self, mck_get_rdf, mck_get_vol, mck_get_sg, mck_move_vol,
              mck_return_vol, mck_is_vol):
  
          array = self.data.array
          srp = self.data.srp
          device_id = self.data.device_id
          volume = self.data.test_volume
          volume_name = self.data.volume_id
          extra_specs = deepcopy(self.data.rep_extra_specs)
          target_slo = self.data.slo_silver
          target_workload = self.data.workload
          target_extra_specs = deepcopy(self.data.rep_extra_specs)
          target_extra_specs[utils.DISABLECOMPRESSION] = False
          group_name = self.data.rdf_managed_async_grp
          extra_specs[utils.REP_CONFIG] = self.data.rep_config_async
          target_extra_specs[utils.REP_CONFIG] = self.data.rep_config_async
  
          success, target_sg_name = self.common._retype_volume(
              array, srp, device_id, volume, volume_name, extra_specs,
              target_slo, target_workload, target_extra_specs, remote=True)
  
          mck_get_rdf.assert_called_once_with(self.data.rep_config_async)
          mck_get_vol.assert_called_once_with(array, device_id)
          mck_get_sg.assert_called_once_with(
              array, srp, target_slo, target_workload, extra_specs,
              False, True, target_extra_specs['rep_mode'])
          mck_move_vol.assert_called_once_with(
              array, device_id, self.data.volume_details[0]['storageGroupId'][0],
              group_name, extra_specs, force=True, parent_sg=None)
          mck_return_vol.assert_called_once_with(
              array, volume, device_id, volume_name, extra_specs)
          mck_is_vol.assert_called_once_with(array, device_id, group_name)
          self.assertTrue(success)
          self.assertEqual(group_name, target_sg_name)
  
      @mock.patch.object(
          utils.PowerMaxUtils, 'get_port_name_label',
          return_value='my_pg')
      @mock.patch.object(
          utils.PowerMaxUtils, 'get_volume_attached_hostname',
          return_value='HostX')
      @mock.patch.object(
          rest.PowerMaxRest, 'is_volume_in_storagegroup', return_value=True)
      @mock.patch.object(
          masking.PowerMaxMasking, 'return_volume_to_volume_group')
      @mock.patch.object(
          masking.PowerMaxMasking, 'move_volume_between_storage_groups')
      @mock.patch.object(
          masking.PowerMaxMasking, 'add_child_sg_to_parent_sg')
      @mock.patch.object(
          provision.PowerMaxProvision, 'create_storage_group')
      @mock.patch.object(
          rest.PowerMaxRest, 'get_storage_group',
          side_effect=[None, tpd.PowerMaxData.volume_info_dict])
      @mock.patch.object(
          rest.PowerMaxRest, 'get_volume',
          return_value=tpd.PowerMaxData.volume_details[0])
      @mock.patch.object(
          utils.PowerMaxUtils, 'get_rdf_management_group_name',
          return_value=tpd.PowerMaxData.rdf_managed_async_grp)
      def test_retype_volume_attached(
              self, mck_get_rdf, mck_get_vol, mck_get_sg, mck_create, mck_add,
              mck_move_vol, mck_return_vol, mck_is_vol, mck_host, mck_pg):
  
          array = self.data.array
          srp = self.data.srp
          device_id = self.data.device_id
          volume = self.data.test_attached_volume
          volume_name = self.data.volume_id
          extra_specs = self.data.rep_extra_specs
          target_slo = self.data.slo_silver
          target_workload = self.data.workload
          target_extra_specs = deepcopy(self.data.rep_extra_specs)
          target_extra_specs[utils.DISABLECOMPRESSION] = False
          target_extra_specs[utils.REP_CONFIG] = self.data.rep_config_sync
  
          success, target_sg_name = self.common._retype_volume(
              array, srp, device_id, volume, volume_name, extra_specs,
              target_slo, target_workload, target_extra_specs)
          mck_get_rdf.assert_called_once()
          mck_get_vol.assert_called_once()
          mck_create.assert_called_once()
          mck_add.assert_called_once()
          mck_move_vol.assert_called_once()
          mck_return_vol.assert_called_once()
          mck_is_vol.assert_called_once()
          self.assertEqual(2, mck_get_sg.call_count)
          self.assertTrue(success)
  
      @mock.patch.object(
          utils.PowerMaxUtils, 'get_volume_attached_hostname', return_value=None)
      @mock.patch.object(
          rest.PowerMaxRest, 'get_volume',
          return_value=tpd.PowerMaxData.volume_details[0])
      @mock.patch.object(
          utils.PowerMaxUtils, 'get_rdf_management_group_name',
          return_value=tpd.PowerMaxData.rdf_managed_async_grp)
      def test_retype_volume_attached_no_host_fail(
              self, mck_get_rdf, mck_get_vol, mck_get_host):
  
          array = self.data.array
          srp = self.data.srp
          device_id = self.data.device_id
          volume = self.data.test_attached_volume
          volume_name = self.data.volume_id
          extra_specs = self.data.rep_extra_specs
          target_slo = self.data.slo_silver
          target_workload = self.data.workload
          target_extra_specs = deepcopy(self.data.rep_extra_specs)
          target_extra_specs[utils.DISABLECOMPRESSION] = False
          target_extra_specs[utils.REP_CONFIG] = self.data.rep_config_async
  
          success, target_sg_name = self.common._retype_volume(
              array, srp, device_id, volume, volume_name, extra_specs,
              target_slo, target_workload, target_extra_specs)
          mck_get_rdf.assert_called_once()
          mck_get_vol.assert_called_once()
          self.assertFalse(success)
          self.assertIsNone(target_sg_name)
  
      @mock.patch.object(rest.PowerMaxRest, 'is_volume_in_storagegroup',
                         return_value=False)
      @mock.patch.object(masking.PowerMaxMasking,
                         'return_volume_to_volume_group')
      @mock.patch.object(masking.PowerMaxMasking,
                         'move_volume_between_storage_groups')
      @mock.patch.object(
          masking.PowerMaxMasking, 'get_or_create_default_storage_group',
          return_value=tpd.PowerMaxData.rdf_managed_async_grp)
      @mock.patch.object(rest.PowerMaxRest, 'get_volume',
                         return_value=tpd.PowerMaxData.volume_details[0])
      @mock.patch.object(utils.PowerMaxUtils, 'get_rdf_management_group_name',
                         return_value=tpd.PowerMaxData.rdf_managed_async_grp)
      def test_retype_volume_detached_vol_not_in_sg_fail(
              self, mck_get_rdf, mck_get_vol, mck_get_sg, mck_move_vol,
              mck_return_vol, mck_is_vol):
  
          array = self.data.array
          srp = self.data.srp
          device_id = self.data.device_id
          volume = self.data.test_volume
          volume_name = self.data.volume_id
          extra_specs = deepcopy(self.data.rep_extra_specs)
          target_slo = self.data.slo_silver
          target_workload = self.data.workload
          target_extra_specs = deepcopy(self.data.rep_extra_specs)
          target_extra_specs[utils.DISABLECOMPRESSION] = False
          extra_specs[utils.REP_CONFIG] = self.data.rep_config_async
          target_extra_specs[utils.REP_CONFIG] = self.data.rep_config_async
  
          success, target_sg_name = self.common._retype_volume(
              array, srp, device_id, volume, volume_name, extra_specs,
              target_slo, target_workload, target_extra_specs, remote=True)
          self.assertFalse(success)
          self.assertIsNone(target_sg_name)
  
      @mock.patch.object(
          rest.PowerMaxRest, 'rename_volume')
      @mock.patch.object(
          rest.PowerMaxRest, 'get_rdf_pair_volume',
          return_value=tpd.PowerMaxData.rdf_group_vol_details)
      def test_get_and_set_remote_device_uuid(self, mck_get_pair, mck_rename):
          extra_specs = self.data.rep_extra_specs
          rep_extra_specs = self.data.rep_extra_specs_mgmt
          volume_dict = {'device_id': self.data.device_id,
                         'device_uuid': self.data.volume_id}
  
          remote_vol = self.common.get_and_set_remote_device_uuid(
              extra_specs, rep_extra_specs, volume_dict)
          self.assertEqual(remote_vol, self.data.device_id2)
  
      @mock.patch.object(utils.PowerMaxUtils, 'get_volume_group_utils',
                         return_value=(None, {'interval': 1, 'retries': 1}))
      def test_get_volume_group_info(self, mock_group_utils):
          self.common.interval = 1
          self.common.retries = 1
          with mock.patch.object(
                  self.common, '_get_configuration_value') as mock_array:
              self.common._get_volume_group_info(
                  self.data.test_group_1)
              mock_group_utils.assert_called_once_with(
                  self.data.test_group_1, self.common.interval,
                  self.common.retries)
              mock_array.assert_called_once()
  
      def test_get_performance_config(self):
          ref_cinder_conf = tpfo.FakeConfiguration(
              None, 'ProvisionTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
              vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
              san_api_port=8443, vmax_port_groups=[self.data.port_group_name_f],
              load_balance=True, load_balance_real_time=True,
              load_data_format='avg', load_look_back=60,
              load_look_back_real_time=10, port_group_load_metric='PercentBusy',
              port_load_metric='PercentBusy')
  
          ref_perf_conf = self.data.performance_config
          volume_utils.get_max_over_subscription_ratio = mock.Mock()
          rest.PowerMaxRest._establish_rest_session = mock.Mock(
              return_value=tpfo.FakeRequestsSession())
          driver = fc.PowerMaxFCDriver(configuration=ref_cinder_conf)
          self.assertEqual(ref_perf_conf, driver.common.performance.config)
  
      def test_select_port_group_for_extra_specs_volume_type(self):
          """Test _select_port_group_for_extra_specs PG in volume-type."""
          extra_specs = {utils.PORTGROUPNAME: self.data.port_group_name_i}
          pool_record = {}
          port_group = self.common._select_port_group_for_extra_specs(
              extra_specs, pool_record)
          self.assertEqual(self.data.port_group_name_i, port_group)
  
      def test_select_port_group_for_extra_specs_cinder_conf_single(self):
          """Test _select_port_group_for_extra_specs single PG in cinder conf."""
          extra_specs = {}
          pool_record = {utils.PORT_GROUP: [self.data.port_group_name_i]}
          port_group = self.common._select_port_group_for_extra_specs(
              extra_specs, pool_record)
          self.assertEqual(self.data.port_group_name_i, port_group)
  
      def test_select_port_group_for_extra_specs_cinder_conf_multi(self):
          """Test _select_port_group_for_extra_specs multi PG in cinder conf.
  
          Random selection is used, no performance configuration supplied.
          """
          extra_specs = {}
          pool_record = {utils.PORT_GROUP: self.data.perf_port_groups}
          port_group = self.common._select_port_group_for_extra_specs(
              extra_specs, pool_record)
          self.assertIn(port_group, self.data.perf_port_groups)
  
      def test_select_port_group_for_extra_specs_load_balanced(self):
          """Test _select_port_group_for_extra_specs multi PG in cinder conf.
  
          Load balanced selection is used, performance configuration supplied.
          """
          extra_specs = {utils.ARRAY: self.data.array}
          pool_record = {utils.PORT_GROUP: self.data.perf_port_groups}
          self.common.performance.config = self.data.performance_config
          with mock.patch.object(
                  self.common.performance, 'process_port_group_load',
                  side_effect=(
                      self.common.performance.process_port_group_load)) as (
                          mck_process):
              port_group = self.common._select_port_group_for_extra_specs(
                  extra_specs, pool_record, init_conn=True)
              mck_process.assert_called_once_with(
                  self.data.array, self.data.perf_port_groups)
              self.assertIn(port_group, self.data.perf_port_groups)
  
      def test_select_port_group_for_extra_specs_exception(self):
          """Test _select_port_group_for_extra_specs exception."""
          self.assertRaises(
              exception.VolumeBackendAPIException,
              self.common._select_port_group_for_extra_specs, {}, {})
  