"Fossies" - the Fresh Open Source Software Archive

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


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

    1 # Copyright 2016 Infinidat Ltd.
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 """Unit tests for INFINIDAT InfiniBox volume driver."""
   16 
   17 import functools
   18 import mock
   19 from oslo_utils import units
   20 import platform
   21 import socket
   22 
   23 from cinder import exception
   24 from cinder import test
   25 from cinder import version
   26 from cinder.volume import configuration
   27 from cinder.volume.drivers import infinidat
   28 
   29 
   30 TEST_WWN_1 = '00:11:22:33:44:55:66:77'
   31 TEST_WWN_2 = '11:11:22:33:44:55:66:77'
   32 
   33 TEST_IP_ADDRESS = '1.1.1.1'
   34 TEST_IQN = 'iqn.2012-07.org.fake:01'
   35 TEST_ISCSI_TCP_PORT = 3260
   36 
   37 TEST_TARGET_PORTAL = '{}:{}'.format(TEST_IP_ADDRESS, TEST_ISCSI_TCP_PORT)
   38 
   39 test_volume = mock.Mock(id=1, size=1, volume_type_id=1)
   40 test_snapshot = mock.Mock(id=2, volume=test_volume, volume_id='1')
   41 test_clone = mock.Mock(id=3, size=1)
   42 test_group = mock.Mock(id=4)
   43 test_snapgroup = mock.Mock(id=5, group=test_group)
   44 test_connector = dict(wwpns=[TEST_WWN_1],
   45                       initiator=TEST_IQN)
   46 
   47 
   48 def skip_driver_setup(func):
   49     @functools.wraps(func)
   50     def f(*args, **kwargs):
   51         return func(*args, **kwargs)
   52     f.__skip_driver_setup = True
   53     return f
   54 
   55 
   56 class FakeInfinisdkException(Exception):
   57     pass
   58 
   59 
   60 class InfiniboxDriverTestCaseBase(test.TestCase):
   61     def _test_skips_driver_setup(self):
   62         test_method_name = self.id().split('.')[-1]
   63         test_method = getattr(self, test_method_name)
   64         return getattr(test_method, '__skip_driver_setup', False)
   65 
   66     def setUp(self):
   67         super(InfiniboxDriverTestCaseBase, self).setUp()
   68 
   69         # create mock configuration
   70         self.configuration = mock.Mock(spec=configuration.Configuration)
   71         self.configuration.infinidat_storage_protocol = 'fc'
   72         self.configuration.san_ip = 'mockbox'
   73         self.configuration.infinidat_pool_name = 'mockpool'
   74         self.configuration.san_thin_provision = True
   75         self.configuration.san_login = 'user'
   76         self.configuration.san_password = 'pass'
   77         self.configuration.volume_backend_name = 'mock'
   78         self.configuration.volume_dd_blocksize = '1M'
   79         self.configuration.use_multipath_for_image_xfer = False
   80         self.configuration.enforce_multipath_for_image_xfer = False
   81         self.configuration.num_volume_device_scan_tries = 1
   82         self.configuration.san_is_local = False
   83         self.configuration.chap_username = None
   84         self.configuration.chap_password = None
   85         self.configuration.infinidat_use_compression = None
   86         self.configuration.max_over_subscription_ratio = 10.0
   87 
   88         self.driver = infinidat.InfiniboxVolumeDriver(
   89             configuration=self.configuration)
   90         self._system = self._infinibox_mock()
   91         # mock external library dependencies
   92         infinisdk = self.patch("cinder.volume.drivers.infinidat.infinisdk")
   93         capacity = self.patch("cinder.volume.drivers.infinidat.capacity")
   94         self._iqn = self.patch("cinder.volume.drivers.infinidat.iqn")
   95         self._wwn = self.patch("cinder.volume.drivers.infinidat.wwn")
   96         self._wwn.WWN = mock.Mock
   97         self._iqn.IQN = mock.Mock
   98         capacity.byte = 1
   99         capacity.GiB = units.Gi
  100         infinisdk.core.exceptions.InfiniSDKException = FakeInfinisdkException
  101         infinisdk.InfiniBox.return_value = self._system
  102 
  103         if not self._test_skips_driver_setup():
  104             self.driver.do_setup(None)
  105 
  106     def _infinibox_mock(self):
  107         result = mock.Mock()
  108         self._mock_volume = mock.Mock()
  109         self._mock_volume.get_size.return_value = 1 * units.Gi
  110         self._mock_volume.has_children.return_value = False
  111         self._mock_volume.get_logical_units.return_value = []
  112         self._mock_volume.create_snapshot.return_value = self._mock_volume
  113         self._mock_host = mock.Mock()
  114         self._mock_host.get_luns.return_value = []
  115         self._mock_host.map_volume().get_lun.return_value = 1
  116         self._mock_pool = mock.Mock()
  117         self._mock_pool.get_free_physical_capacity.return_value = units.Gi
  118         self._mock_pool.get_physical_capacity.return_value = units.Gi
  119         self._mock_ns = mock.Mock()
  120         self._mock_ns.get_ips.return_value = [
  121             mock.Mock(ip_address=TEST_IP_ADDRESS, enabled=True)]
  122         self._mock_ns.get_properties.return_value = mock.Mock(
  123             iscsi_iqn=TEST_IQN, iscsi_tcp_port=TEST_ISCSI_TCP_PORT)
  124         self._mock_group = mock.Mock()
  125         self._mock_qos_policy = mock.Mock()
  126         result.volumes.safe_get.return_value = self._mock_volume
  127         result.volumes.create.return_value = self._mock_volume
  128         result.pools.safe_get.return_value = self._mock_pool
  129         result.hosts.safe_get.return_value = self._mock_host
  130         result.cons_groups.safe_get.return_value = self._mock_group
  131         result.cons_groups.create.return_value = self._mock_group
  132         result.hosts.create.return_value = self._mock_host
  133         result.network_spaces.safe_get.return_value = self._mock_ns
  134         result.components.nodes.get_all.return_value = []
  135         result.qos_policies.create.return_value = self._mock_qos_policy
  136         result.qos_policies.safe_get.return_value = None
  137         return result
  138 
  139     def _raise_infinisdk(self, *args, **kwargs):
  140         raise FakeInfinisdkException()
  141 
  142 
  143 class InfiniboxDriverTestCase(InfiniboxDriverTestCaseBase):
  144     def _generate_mock_object_metadata(self, cinder_object):
  145         return {"system": "openstack",
  146                 "openstack_version": version.version_info.release_string(),
  147                 "cinder_id": cinder_object.id,
  148                 "cinder_name": cinder_object.name,
  149                 "host.created_by": infinidat._INFINIDAT_CINDER_IDENTIFIER}
  150 
  151     def _validate_object_metadata(self, infinidat_object, cinder_object):
  152         infinidat_object.set_metadata_from_dict.assert_called_once_with(
  153             self._generate_mock_object_metadata(cinder_object))
  154 
  155     def _generate_mock_host_metadata(self):
  156         return {"system": "openstack",
  157                 "openstack_version": version.version_info.release_string(),
  158                 "hostname": socket.gethostname(),
  159                 "platform": platform.platform(),
  160                 "host.created_by": infinidat._INFINIDAT_CINDER_IDENTIFIER}
  161 
  162     def _validate_host_metadata(self):
  163         self._mock_host.set_metadata_from_dict.assert_called_once_with(
  164             self._generate_mock_host_metadata())
  165 
  166     @skip_driver_setup
  167     def test__setup_and_get_system_object(self):
  168         # This test should skip the driver setup, as it generates more calls to
  169         # the add_auto_retry, set_source_identifier and login methods:
  170         auth = (self.configuration.san_login,
  171                 self.configuration.san_password)
  172 
  173         self.driver._setup_and_get_system_object(
  174             self.configuration.san_ip, auth)
  175 
  176         self._system.api.add_auto_retry.assert_called_once()
  177         self._system.api.set_source_identifier.assert_called_once_with(
  178             infinidat._INFINIDAT_CINDER_IDENTIFIER)
  179         self._system.login.assert_called_once()
  180 
  181     def test_initialize_connection(self):
  182         self._system.hosts.safe_get.return_value = None
  183         result = self.driver.initialize_connection(test_volume, test_connector)
  184         self.assertEqual(1, result["data"]["target_lun"])
  185 
  186     def test_initialize_connection_host_exists(self):
  187         result = self.driver.initialize_connection(test_volume, test_connector)
  188         self.assertEqual(1, result["data"]["target_lun"])
  189 
  190     def test_initialize_connection_mapping_exists(self):
  191         mock_mapping = mock.Mock()
  192         mock_mapping.get_volume.return_value = self._mock_volume
  193         mock_mapping.get_lun.return_value = 888
  194         self._mock_host.get_luns.return_value = [mock_mapping]
  195         result = self.driver.initialize_connection(test_volume, test_connector)
  196         self.assertEqual(888, result["data"]["target_lun"])
  197 
  198     def test_initialize_connection_volume_doesnt_exist(self):
  199         self._system.volumes.safe_get.return_value = None
  200         self.assertRaises(exception.InvalidVolume,
  201                           self.driver.initialize_connection,
  202                           test_volume, test_connector)
  203 
  204     def test_initialize_connection_create_fails(self):
  205         self._system.hosts.safe_get.return_value = None
  206         self._system.hosts.create.side_effect = self._raise_infinisdk
  207         self.assertRaises(exception.VolumeBackendAPIException,
  208                           self.driver.initialize_connection,
  209                           test_volume, test_connector)
  210 
  211     def test_initialize_connection_map_fails(self):
  212         self._mock_host.map_volume.side_effect = self._raise_infinisdk
  213         self.assertRaises(exception.VolumeBackendAPIException,
  214                           self.driver.initialize_connection,
  215                           test_volume, test_connector)
  216 
  217     def test_initialize_connection_metadata(self):
  218         self._system.hosts.safe_get.return_value = None
  219         self.driver.initialize_connection(test_volume, test_connector)
  220         self._validate_host_metadata()
  221 
  222     def test_terminate_connection(self):
  223         self.driver.terminate_connection(test_volume, test_connector)
  224 
  225     def test_terminate_connection_delete_host(self):
  226         self._mock_host.get_luns.return_value = [object()]
  227         self.driver.terminate_connection(test_volume, test_connector)
  228         self.assertEqual(0, self._mock_host.safe_delete.call_count)
  229         self._mock_host.get_luns.return_value = []
  230         self.driver.terminate_connection(test_volume, test_connector)
  231         self.assertEqual(1, self._mock_host.safe_delete.call_count)
  232 
  233     def test_terminate_connection_volume_doesnt_exist(self):
  234         self._system.volumes.safe_get.return_value = None
  235         self.assertRaises(exception.InvalidVolume,
  236                           self.driver.terminate_connection,
  237                           test_volume, test_connector)
  238 
  239     def test_terminate_connection_api_fail(self):
  240         self._mock_host.unmap_volume.side_effect = self._raise_infinisdk
  241         self.assertRaises(exception.VolumeBackendAPIException,
  242                           self.driver.terminate_connection,
  243                           test_volume, test_connector)
  244 
  245     def test_get_volume_stats_refreshes(self):
  246         result = self.driver.get_volume_stats()
  247         self.assertEqual(1, result["free_capacity_gb"])
  248         # change the "free space" in the pool
  249         self._mock_pool.get_free_physical_capacity.return_value = 0
  250         # no refresh - free capacity should stay the same
  251         result = self.driver.get_volume_stats(refresh=False)
  252         self.assertEqual(1, result["free_capacity_gb"])
  253         # refresh - free capacity should change to 0
  254         result = self.driver.get_volume_stats(refresh=True)
  255         self.assertEqual(0, result["free_capacity_gb"])
  256 
  257     def test_get_volume_stats_pool_not_found(self):
  258         self._system.pools.safe_get.return_value = None
  259         self.assertRaises(exception.VolumeDriverException,
  260                           self.driver.get_volume_stats)
  261 
  262     def test_get_volume_stats_max_over_subscription_ratio(self):
  263         result = self.driver.get_volume_stats()
  264         # check the defaults defined in setUp
  265         self.assertEqual(10.0, result['max_over_subscription_ratio'])
  266         self.assertTrue(result['thin_provisioning_support'])
  267         self.assertFalse(result['thick_provisioning_support'])
  268 
  269     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  270     def test_create_volume(self, *mocks):
  271         self.driver.create_volume(test_volume)
  272 
  273     def test_create_volume_pool_not_found(self):
  274         self._system.pools.safe_get.return_value = None
  275         self.assertRaises(exception.VolumeDriverException,
  276                           self.driver.create_volume, test_volume)
  277 
  278     def test_create_volume_api_fail(self):
  279         self._system.pools.safe_get.side_effect = self._raise_infinisdk
  280         self.assertRaises(exception.VolumeBackendAPIException,
  281                           self.driver.create_volume, test_volume)
  282 
  283     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  284     def test_create_volume_metadata(self, *mocks):
  285         self.driver.create_volume(test_volume)
  286         self._validate_object_metadata(self._mock_volume, test_volume)
  287 
  288     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  289     def test_create_volume_compression_enabled(self, *mocks):
  290         self.configuration.infinidat_use_compression = True
  291         self.driver.create_volume(test_volume)
  292         self.assertTrue(
  293             self._system.volumes.create.call_args[1]["compression_enabled"]
  294         )
  295 
  296     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  297     def test_create_volume_compression_not_enabled(self, *mocks):
  298         self.configuration.infinidat_use_compression = False
  299         self.driver.create_volume(test_volume)
  300         self.assertFalse(
  301             self._system.volumes.create.call_args[1]["compression_enabled"]
  302         )
  303 
  304     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  305     def test_create_volume_compression_not_available(self, *mocks):
  306         self._system.compat.has_compression.return_value = False
  307         self.driver.create_volume(test_volume)
  308         self.assertNotIn(
  309             "compression_enabled",
  310             self._system.volumes.create.call_args[1]
  311         )
  312 
  313     def test_delete_volume(self):
  314         self.driver.delete_volume(test_volume)
  315 
  316     def test_delete_volume_doesnt_exist(self):
  317         self._system.volumes.safe_get.return_value = None
  318         # should not raise an exception
  319         self.driver.delete_volume(test_volume)
  320 
  321     def test_delete_volume_with_children(self):
  322         self._mock_volume.has_children.return_value = True
  323         self.assertRaises(exception.VolumeIsBusy,
  324                           self.driver.delete_volume, test_volume)
  325 
  326     def test_extend_volume(self):
  327         self.driver.extend_volume(test_volume, 2)
  328         self._mock_volume.resize.assert_called_with(1 * units.Gi)
  329 
  330     def test_extend_volume_api_fail(self):
  331         self._mock_volume.resize.side_effect = self._raise_infinisdk
  332         self.assertRaises(exception.VolumeBackendAPIException,
  333                           self.driver.extend_volume, test_volume, 2)
  334 
  335     def test_create_snapshot(self):
  336         self.driver.create_snapshot(test_snapshot)
  337 
  338     def test_create_snapshot_metadata(self):
  339         self._mock_volume.create_snapshot.return_value = self._mock_volume
  340         self.driver.create_snapshot(test_snapshot)
  341         self._validate_object_metadata(self._mock_volume, test_snapshot)
  342 
  343     def test_create_snapshot_volume_doesnt_exist(self):
  344         self._system.volumes.safe_get.return_value = None
  345         self.assertRaises(exception.InvalidVolume,
  346                           self.driver.create_snapshot, test_snapshot)
  347 
  348     def test_create_snapshot_api_fail(self):
  349         self._mock_volume.create_snapshot.side_effect = self._raise_infinisdk
  350         self.assertRaises(exception.VolumeBackendAPIException,
  351                           self.driver.create_snapshot, test_snapshot)
  352 
  353     @mock.patch("cinder.volume.utils.copy_volume")
  354     @mock.patch("cinder.utils.brick_get_connector")
  355     @mock.patch("cinder.utils.brick_get_connector_properties",
  356                 return_value=test_connector)
  357     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  358     def test_create_volume_from_snapshot(self, *mocks):
  359         self.driver.create_volume_from_snapshot(test_clone, test_snapshot)
  360 
  361     def test_create_volume_from_snapshot_doesnt_exist(self):
  362         self._system.volumes.safe_get.return_value = None
  363         self.assertRaises(exception.InvalidSnapshot,
  364                           self.driver.create_volume_from_snapshot,
  365                           test_clone, test_snapshot)
  366 
  367     def test_create_volume_from_snapshot_create_fails(self):
  368         self._mock_volume.create_snapshot.side_effect = self._raise_infinisdk
  369         self.assertRaises(exception.VolumeBackendAPIException,
  370                           self.driver.create_volume_from_snapshot,
  371                           test_clone, test_snapshot)
  372 
  373     @mock.patch("cinder.utils.brick_get_connector_properties",
  374                 return_value=test_connector)
  375     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  376     def test_create_volume_from_snapshot_map_fails(self, *mocks):
  377         self._mock_host.map_volume.side_effect = self._raise_infinisdk
  378         self.assertRaises(exception.VolumeBackendAPIException,
  379                           self.driver.create_volume_from_snapshot,
  380                           test_clone, test_snapshot)
  381 
  382     @mock.patch("cinder.volume.utils.copy_volume")
  383     @mock.patch("cinder.utils.brick_get_connector")
  384     @mock.patch("cinder.utils.brick_get_connector_properties",
  385                 return_value=test_connector)
  386     def test_create_volume_from_snapshot_delete_clone_fails(self, *mocks):
  387         self._mock_volume.delete.side_effect = self._raise_infinisdk
  388         self.assertRaises(exception.VolumeBackendAPIException,
  389                           self.driver.create_volume_from_snapshot,
  390                           test_clone, test_snapshot)
  391 
  392     def test_delete_snapshot(self):
  393         self.driver.delete_snapshot(test_snapshot)
  394 
  395     def test_delete_snapshot_doesnt_exist(self):
  396         self._system.volumes.safe_get.return_value = None
  397         # should not raise an exception
  398         self.driver.delete_snapshot(test_snapshot)
  399 
  400     def test_delete_snapshot_api_fail(self):
  401         self._mock_volume.safe_delete.side_effect = self._raise_infinisdk
  402         self.assertRaises(exception.VolumeBackendAPIException,
  403                           self.driver.delete_snapshot, test_snapshot)
  404 
  405     @mock.patch("cinder.volume.utils.copy_volume")
  406     @mock.patch("cinder.utils.brick_get_connector")
  407     @mock.patch("cinder.utils.brick_get_connector_properties",
  408                 return_value=test_connector)
  409     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  410     def test_create_cloned_volume(self, *mocks):
  411         self.driver.create_cloned_volume(test_clone, test_volume)
  412 
  413     def test_create_cloned_volume_volume_already_mapped(self):
  414         mock_mapping = mock.Mock()
  415         mock_mapping.get_volume.return_value = self._mock_volume
  416         self._mock_volume.get_logical_units.return_value = [mock_mapping]
  417         self.assertRaises(exception.VolumeBackendAPIException,
  418                           self.driver.create_cloned_volume,
  419                           test_clone, test_volume)
  420 
  421     def test_create_cloned_volume_create_fails(self):
  422         self._system.volumes.create.side_effect = self._raise_infinisdk
  423         self.assertRaises(exception.VolumeBackendAPIException,
  424                           self.driver.create_cloned_volume,
  425                           test_clone, test_volume)
  426 
  427     @mock.patch("cinder.utils.brick_get_connector_properties",
  428                 return_value=test_connector)
  429     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  430     def test_create_cloned_volume_map_fails(self, *mocks):
  431         self._mock_host.map_volume.side_effect = self._raise_infinisdk
  432         self.assertRaises(exception.VolumeBackendAPIException,
  433                           self.driver.create_cloned_volume,
  434                           test_clone, test_volume)
  435 
  436     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  437                 return_value=True)
  438     def test_create_group(self, *mocks):
  439         self.driver.create_group(None, test_group)
  440 
  441     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  442                 return_value=True)
  443     def test_create_group_metadata(self, *mocks):
  444         self.driver.create_group(None, test_group)
  445         self._validate_object_metadata(self._mock_group, test_group)
  446 
  447     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  448                 return_value=True)
  449     def test_create_group_twice(self, *mocks):
  450         self.driver.create_group(None, test_group)
  451         self.driver.create_group(None, test_group)
  452 
  453     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  454                 return_value=True)
  455     def test_create_group_api_fail(self, *mocks):
  456         self._system.cons_groups.create.side_effect = self._raise_infinisdk
  457         self.assertRaises(exception.VolumeBackendAPIException,
  458                           self.driver.create_group,
  459                           None, test_group)
  460 
  461     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  462                 return_value=True)
  463     def test_delete_group(self, *mocks):
  464         self.driver.delete_group(None, test_group, [test_volume])
  465 
  466     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  467                 return_value=True)
  468     def test_delete_group_doesnt_exist(self, *mocks):
  469         self._system.cons_groups.safe_get.return_value = None
  470         self.driver.delete_group(None, test_group, [test_volume])
  471 
  472     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  473                 return_value=True)
  474     def test_delete_group_api_fail(self, *mocks):
  475         self._mock_group.safe_delete.side_effect = self._raise_infinisdk
  476         self.assertRaises(exception.VolumeBackendAPIException,
  477                           self.driver.delete_group,
  478                           None, test_group, [test_volume])
  479 
  480     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  481                 return_value=True)
  482     def test_update_group_add_and_remove(self, *mocks):
  483         self.driver.update_group(None, test_group,
  484                                  [test_volume], [test_volume])
  485 
  486     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  487                 return_value=True)
  488     def test_update_group_api_fail(self, *mocks):
  489         self._mock_group.add_member.side_effect = self._raise_infinisdk
  490         self.assertRaises(exception.VolumeBackendAPIException,
  491                           self.driver.update_group,
  492                           None, test_group,
  493                           [test_volume], [test_volume])
  494 
  495     @mock.patch("cinder.volume.utils.copy_volume")
  496     @mock.patch("cinder.utils.brick_get_connector")
  497     @mock.patch("cinder.utils.brick_get_connector_properties",
  498                 return_value=test_connector)
  499     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  500                 return_value=True)
  501     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  502     def test_create_group_from_src_snaps(self, *mocks):
  503         self.driver.create_group_from_src(None, test_group, [test_volume],
  504                                           test_snapgroup, [test_snapshot],
  505                                           None, None)
  506 
  507     @mock.patch("cinder.volume.utils.copy_volume")
  508     @mock.patch("cinder.utils.brick_get_connector")
  509     @mock.patch("cinder.utils.brick_get_connector_properties",
  510                 return_value=test_connector)
  511     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  512                 return_value=True)
  513     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  514     def test_create_group_from_src_vols(self, *mocks):
  515         self.driver.create_group_from_src(None, test_group, [test_volume],
  516                                           None, None,
  517                                           test_group, [test_volume])
  518 
  519     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  520                 return_value=True)
  521     def test_create_group_snap(self, *mocks):
  522         mock_snapgroup = mock.Mock()
  523         mock_snapgroup.get_members.return_value = [self._mock_volume]
  524         self._mock_volume.get_parent.return_value = self._mock_volume
  525         self._mock_volume.get_name.return_value = ''
  526         self._mock_group.create_snapshot.return_value = mock_snapgroup
  527         self.driver.create_group_snapshot(None,
  528                                           test_snapgroup,
  529                                           [test_snapshot])
  530 
  531     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  532                 return_value=True)
  533     def test_create_group_snap_api_fail(self, *mocks):
  534         self._mock_group.create_snapshot.side_effect = self._raise_infinisdk
  535         self.assertRaises(exception.VolumeBackendAPIException,
  536                           self.driver.create_group_snapshot, None,
  537                           test_snapgroup, [test_snapshot])
  538 
  539     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  540                 return_value=True)
  541     def test_delete_group_snap(self, *mocks):
  542         self.driver.delete_group_snapshot(None,
  543                                           test_snapgroup,
  544                                           [test_snapshot])
  545 
  546     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  547                 return_value=True)
  548     def test_delete_group_snap_does_not_exist(self, *mocks):
  549         self._system.cons_groups.safe_get.return_value = None
  550         self.driver.delete_group_snapshot(None,
  551                                           test_snapgroup,
  552                                           [test_snapshot])
  553 
  554     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  555                 return_value=True)
  556     def test_delete_group_snap_invalid_group(self, *mocks):
  557         self._mock_group.is_snapgroup.return_value = False
  558         self.assertRaises(exception.InvalidGroupSnapshot,
  559                           self.driver.delete_group_snapshot,
  560                           None, test_snapgroup, [test_snapshot])
  561 
  562     @mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type',
  563                 return_value=True)
  564     def test_delete_group_snap_api_fail(self, *mocks):
  565         self._mock_group.safe_delete.side_effect = self._raise_infinisdk
  566         self.assertRaises(exception.VolumeBackendAPIException,
  567                           self.driver.delete_group_snapshot,
  568                           None, test_snapgroup, [test_snapshot])
  569 
  570     def test_terminate_connection_force_detach(self):
  571         mock_infinidat_host = mock.Mock()
  572         mock_infinidat_host.get_ports.return_value = [
  573             self._wwn.WWN(TEST_WWN_1)]
  574         mock_mapping = mock.Mock()
  575         mock_mapping.get_host.return_value = mock_infinidat_host
  576         self._mock_volume.get_logical_units.return_value = [mock_mapping]
  577         # connector is None - force detach - detach all mappings
  578         self.driver.terminate_connection(test_volume, None)
  579         # make sure we actually detached the host mapping
  580         self._mock_host.unmap_volume.assert_called_once()
  581         self._mock_host.safe_delete.assert_called_once()
  582 
  583 
  584 class InfiniboxDriverTestCaseFC(InfiniboxDriverTestCaseBase):
  585     def test_initialize_connection_multiple_wwpns(self):
  586         connector = {'wwpns': [TEST_WWN_1, TEST_WWN_2]}
  587         result = self.driver.initialize_connection(test_volume, connector)
  588         self.assertEqual(1, result["data"]["target_lun"])
  589 
  590     def test_validate_connector(self):
  591         fc_connector = {'wwpns': [TEST_WWN_1, TEST_WWN_2]}
  592         iscsi_connector = {'initiator': TEST_IQN}
  593         self.driver.validate_connector(fc_connector)
  594         self.assertRaises(exception.InvalidConnectorException,
  595                           self.driver.validate_connector, iscsi_connector)
  596 
  597 
  598 class InfiniboxDriverTestCaseISCSI(InfiniboxDriverTestCaseBase):
  599     def setUp(self):
  600         super(InfiniboxDriverTestCaseISCSI, self).setUp()
  601         self.configuration.infinidat_storage_protocol = 'iscsi'
  602         self.configuration.infinidat_iscsi_netspaces = ['netspace1']
  603         self.configuration.use_chap_auth = False
  604         self.driver.do_setup(None)
  605 
  606     def test_setup_without_netspaces_configured(self):
  607         self.configuration.infinidat_iscsi_netspaces = []
  608         self.assertRaises(exception.VolumeDriverException,
  609                           self.driver.do_setup, None)
  610 
  611     def _assert_plurals(self, result, expected_length):
  612         self.assertEqual(expected_length, len(result['data']['target_luns']))
  613         self.assertEqual(expected_length, len(result['data']['target_iqns']))
  614         self.assertEqual(expected_length,
  615                          len(result['data']['target_portals']))
  616         self.assertTrue(all(lun == 1 for lun in result['data']['target_luns']))
  617         self.assertTrue(
  618             all(iqn == test_connector['initiator'] for
  619                 iqn in result['data']['target_iqns']))
  620 
  621         self.assertTrue(all(target_portal == TEST_TARGET_PORTAL for
  622                             target_portal in result['data']['target_portals']))
  623 
  624     def test_initialize_connection(self):
  625         result = self.driver.initialize_connection(test_volume, test_connector)
  626         self.assertEqual(1, result['data']['target_lun'])
  627         self._assert_plurals(result, 1)
  628 
  629     def test_initialize_netspace_does_not_exist(self):
  630         self._system.network_spaces.safe_get.return_value = None
  631         self.assertRaises(exception.VolumeDriverException,
  632                           self.driver.initialize_connection,
  633                           test_volume, test_connector)
  634 
  635     def test_initialize_netspace_has_no_ips(self):
  636         self._mock_ns.get_ips.return_value = []
  637         self.assertRaises(exception.VolumeDriverException,
  638                           self.driver.initialize_connection,
  639                           test_volume, test_connector)
  640 
  641     def test_initialize_connection_with_chap(self):
  642         self.configuration.use_chap_auth = True
  643         result = self.driver.initialize_connection(test_volume, test_connector)
  644         self.assertEqual(1, result['data']['target_lun'])
  645         self.assertEqual('CHAP', result['data']['auth_method'])
  646         self.assertIn('auth_username', result['data'])
  647         self.assertIn('auth_password', result['data'])
  648 
  649     def test_initialize_connection_multiple_netspaces(self):
  650         self.configuration.infinidat_iscsi_netspaces = ['netspace1',
  651                                                         'netspace2']
  652         result = self.driver.initialize_connection(test_volume, test_connector)
  653         self.assertEqual(1, result['data']['target_lun'])
  654         self._assert_plurals(result, 2)
  655 
  656     def test_initialize_connection_plurals(self):
  657         result = self.driver.initialize_connection(test_volume, test_connector)
  658         self._assert_plurals(result, 1)
  659 
  660     def test_terminate_connection(self):
  661         self.driver.terminate_connection(test_volume, test_connector)
  662 
  663     def test_validate_connector(self):
  664         fc_connector = {'wwpns': [TEST_WWN_1, TEST_WWN_2]}
  665         iscsi_connector = {'initiator': TEST_IQN}
  666         self.driver.validate_connector(iscsi_connector)
  667         self.assertRaises(exception.InvalidConnectorException,
  668                           self.driver.validate_connector, fc_connector)
  669 
  670 
  671 class InfiniboxDriverTestCaseQoS(InfiniboxDriverTestCaseBase):
  672     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  673     def test_qos_max_ipos(self, qos_specs):
  674         qos_specs.return_value = {'qos_specs': {'id': 'qos_name',
  675                                                 'consumer': 'back-end',
  676                                                 'specs': {'maxIOPS': 1000,
  677                                                           'maxBWS': None}}}
  678         self.driver.create_volume(test_volume)
  679         self._system.qos_policies.create.assert_called_once()
  680         self._mock_qos_policy.assign_entity.assert_called_once()
  681 
  682     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  683     def test_qos_max_bws(self, qos_specs):
  684         qos_specs.return_value = {'qos_specs': {'id': 'qos_name',
  685                                                 'consumer': 'back-end',
  686                                                 'specs': {'maxIOPS': None,
  687                                                           'maxBWS': 10000}}}
  688         self.driver.create_volume(test_volume)
  689         self._system.qos_policies.create.assert_called_once()
  690         self._mock_qos_policy.assign_entity.assert_called_once()
  691 
  692     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  693     def test_qos_no_compat(self, qos_specs):
  694         qos_specs.return_value = {'qos_specs': {'id': 'qos_name',
  695                                                 'consumer': 'back-end',
  696                                                 'specs': {'maxIOPS': 1000,
  697                                                           'maxBWS': 10000}}}
  698         self._system.compat.has_qos.return_value = False
  699         self.driver.create_volume(test_volume)
  700         self._system.qos_policies.create.assert_not_called()
  701         self._mock_qos_policy.assign_entity.assert_not_called()
  702 
  703     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  704     def test_qos_volume_type_id_none(self, qos_specs):
  705         qos_specs.return_value = {'qos_specs': {'id': 'qos_name',
  706                                                 'consumer': 'back-end',
  707                                                 'specs': {'maxIOPS': 1000,
  708                                                           'maxBWS': 10000}}}
  709         test_volume = mock.Mock(id=1, size=1, volume_type_id=None)
  710         self.driver.create_volume(test_volume)
  711         self._system.qos_policies.create.assert_not_called()
  712         self._mock_qos_policy.assign_entity.assert_not_called()
  713 
  714     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  715     def test_qos_no_specs(self, qos_specs):
  716         qos_specs.return_value = {'qos_specs': None}
  717         self.driver.create_volume(test_volume)
  718         self._system.qos_policies.create.assert_not_called()
  719         self._mock_qos_policy.assign_entity.assert_not_called()
  720 
  721     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  722     def test_qos_front_end(self, qos_specs):
  723         qos_specs.return_value = {'qos_specs': {'id': 'qos_name',
  724                                                 'consumer': 'front-end',
  725                                                 'specs': {'maxIOPS': 1000,
  726                                                           'maxBWS': 10000}}}
  727         self.driver.create_volume(test_volume)
  728         self._system.qos_policies.create.assert_not_called()
  729         self._mock_qos_policy.assign_entity.assert_not_called()
  730 
  731     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  732     def test_qos_specs_empty(self, qos_specs):
  733         qos_specs.return_value = {'qos_specs': {'id': 'qos_name',
  734                                                 'consumer': 'back-end',
  735                                                 'specs': {'maxIOPS': None,
  736                                                           'maxBWS': None}}}
  737         self.driver.create_volume(test_volume)
  738         self._system.qos_policies.create.assert_not_called()
  739         self._mock_qos_policy.assign_entity.assert_not_called()
  740 
  741     @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs")
  742     def test_qos_policy_exists(self, qos_specs):
  743         qos_specs.return_value = {'qos_specs': {'id': 'qos_name',
  744                                                 'consumer': 'back-end',
  745                                                 'specs': {'maxIOPS': 1000,
  746                                                           'maxBWS': 10000}}}
  747         self._system.qos_policies.safe_get.return_value = self._mock_qos_policy
  748         self.driver.create_volume(test_volume)
  749         self._system.qos_policies.create.assert_not_called()
  750         self._mock_qos_policy.assign_entity.assert_called()